Other Parts Discussed in Thread: CC1350,
Tool/software: Code Composer Studio
/****************************************************************************** @file csf.c @brief Collector Specific Functions Group: WCS LPC Target Device: cc13x0 ****************************************************************************** Copyright (c) 2016-2019, Texas Instruments Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Texas Instruments Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *****************************************************************************/ /****************************************************************************** Includes *****************************************************************************/ #include <xdc/std.h> #include <xdc/runtime/Error.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Clock.h> #include <ti/sysbios/hal/Hwi.h> #include <ti/sysbios/knl/Semaphore.h> #include <ti/drivers/Power.h> #include <ti/drivers/PIN.h> #include <string.h> #include <stdlib.h> #include <inc/hw_ints.h> #include <aon_event.h> #include <ioc.h> #include "Board.h" #include "util_timer.h" #include "mac_util.h" #include "board_key.h" #include "board_lcd.h" #include "board_led.h" #ifdef FEATURE_SECURE_COMMISSIONING #include "sm_ti154.h" #endif #if defined(DeviceFamily_CC13X0) || defined(DeviceFamily_CC13X2) #include "board_gpio.h" #endif #include "macconfig.h" #ifdef ONE_PAGE_NV #include "nvocop.h" #else #include "nvoctp.h" #endif #include "api_mac.h" #include "collector.h" #include "cllc.h" #include "csf.h" #include "config.h" #if defined(MT_CSF) #include "mt_csf.h" #endif #ifdef FEATURE_OAD #include <Board.h> #include <ti/drivers/UART.h> #include <ti/drivers/uart/UARTCC26XX.h> #include "uart_printf.h" #include "oad_switch.h" #endif #ifdef OSAL_PORT2TIRTOS #include "osal_port.h" #else #include "icall.h" #endif /****************************************************************************** Constants and definitions *****************************************************************************/ /* Initial timeout value for the tracking clock */ #define TRACKING_INIT_TIMEOUT_VALUE 100 /* NV Item ID - the device's network information */ #define CSF_NV_NETWORK_INFO_ID 0x0001 /* NV Item ID - the number of black list entries */ #define CSF_NV_BLACKLIST_ENTRIES_ID 0x0002 /* NV Item ID - the black list, use sub ID for each record in the list */ #define CSF_NV_BLACKLIST_ID 0x0003 /* NV Item ID - the number of device list entries */ #define CSF_NV_DEVICELIST_ENTRIES_ID 0x0004 /* NV Item ID - the device list, use sub ID for each record in the list */ #define CSF_NV_DEVICELIST_ID 0x0005 /* NV Item ID - this devices frame counter */ #define CSF_NV_FRAMECOUNTER_ID 0x0006 /* NV Item ID - reset reason */ #define CSF_NV_RESET_REASON_ID 0x0007 /* Maximum number of black list entries */ #define CSF_MAX_BLACKLIST_ENTRIES 10 /* Maximum number of device list entries */ #define CSF_MAX_DEVICELIST_ENTRIES CONFIG_MAX_DEVICES /* Maximum sub ID for a blacklist item, this is failsafe. This is not the maximum number of items in the list */ #define CSF_MAX_BLACKLIST_IDS (2*CONFIG_MAX_DEVICES) /* Maximum sub ID for a device list item, this is failsafe. This is not the maximum number of items in the list */ #define CSF_MAX_DEVICELIST_IDS (2*CONFIG_MAX_DEVICES) /* timeout value for trickle timer initialization */ #define TRICKLE_TIMEOUT_VALUE 20 /* timeout value for join timer */ #define JOIN_TIMEOUT_VALUE 20 /* timeout value for config request delay */ #define CONFIG_TIMEOUT_VALUE 1000 /* The increment value needed to save a frame counter. Example, setting this constant to 100, means that the frame counter will be saved when the new frame counter is 100 more than the last saved frame counter. Also, when the get frame counter function reads the value from NV it will add this value to the read value. */ #define FRAME_COUNTER_SAVE_WINDOW 25 /* Value returned from findDeviceListIndex() when not found */ #define DEVICE_INDEX_NOT_FOUND -1 /*! NV driver item ID for reset reason */ #define NVID_RESET {NVINTF_SYSID_APP, CSF_NV_RESET_REASON_ID, 0} /****************************************************************************** External variables *****************************************************************************/ #ifdef NV_RESTORE /*! MAC Configuration Parameters */ extern mac_Config_t Main_user1Cfg; #endif #ifdef FEATURE_SECURE_COMMISSIONING /* Security manager latest state */ extern SM_lastState_t SM_Last_State; /* Need to re-do commissioning*/ extern bool fCommissionRequired; #endif /****************************************************************************** Local variables *****************************************************************************/ /* The application's semaphore */ #ifdef OSAL_PORT2TIRTOS static Semaphore_Handle collectorSem; #else static ICall_Semaphore collectorSem; #endif /* Clock/timer resources */ static Clock_Struct trackingClkStruct; static Clock_Handle trackingClkHandle; static Clock_Struct broadcastClkStruct; static Clock_Handle broadcastClkHandle; /* Clock/timer resources for CLLC */ /* trickle timer */ STATIC Clock_Struct tricklePAClkStruct; STATIC Clock_Handle tricklePAClkHandle; STATIC Clock_Struct tricklePCClkStruct; STATIC Clock_Handle tricklePCClkHandle; /* timer for join permit */ STATIC Clock_Struct joinClkStruct; STATIC Clock_Handle joinClkHandle; /* timer for config request delay */ STATIC Clock_Struct configClkStruct; STATIC Clock_Handle configClkHandle; /* timer for LED blink timeout*/ STATIC Clock_Struct identifyClkStruct; STATIC Clock_Handle identifyClkHandle; /* NV Function Pointers */ static NVINTF_nvFuncts_t *pNV = NULL; static bool started = false; /* The last saved coordinator frame counter */ static uint32_t lastSavedCoordinatorFrameCounter = 0; #if defined(MT_CSF) /*! NV driver item ID for reset reason */ static const NVINTF_itemID_t nvResetId = NVID_RESET; #endif /****************************************************************************** Global variables *****************************************************************************/ /* Key press parameters */ uint8_t Csf_keys; /* pending Csf_events */ uint16_t Csf_events = 0; /* Saved CLLC state */ Cllc_states_t savedCllcState = Cllc_states_initWaiting; /* Permit join setting */ bool permitJoining = false; /****************************************************************************** Local function prototypes *****************************************************************************/ static void processTackingTimeoutCallback(UArg a0); static void processBroadcastTimeoutCallback(UArg a0); static void processKeyChangeCallback(uint8_t keysPressed); static void processPATrickleTimeoutCallback(UArg a0); static void processPCTrickleTimeoutCallback(UArg a0); static void processJoinTimeoutCallback(UArg a0); static void processConfigTimeoutCallback(UArg a0); static void processidentifyTimeoutCallback(UArg a0); static bool addDeviceListItem(Llc_deviceListItem_t *pItem, bool *pNewDevice); static void updateDeviceListItem(Llc_deviceListItem_t *pItem); static int findDeviceListIndex(ApiMac_sAddrExt_t *pAddr); static int findUnusedDeviceListIndex(void); static void saveNumDeviceListEntries(uint16_t numEntries); static int findBlackListIndex(ApiMac_sAddr_t *pAddr); static int findUnusedBlackListIndex(void); static uint16_t getNumBlackListEntries(void); static void saveNumBlackListEntries(uint16_t numEntries); void removeBlackListItem(ApiMac_sAddr_t *pAddr); #if defined(TEST_REMOVE_DEVICE) static void removeTheFirstDevice(void); #else static uint16_t getTheFirstDevice(void); #endif /****************************************************************************** Public Functions *****************************************************************************/ /*! The application calls this function during initialization Public function defined in csf.h */ void Csf_init(void *sem) { #ifdef NV_RESTORE /* Save off the NV Function Pointers */ pNV = &Main_user1Cfg.nvFps; #endif /* Save off the semaphore */ collectorSem = sem; /* Initialize PA/LNA if enabled */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_rangeExtender, (uint8_t)CONFIG_RANGE_EXT_MODE); /* Initialize keys */ if(Board_Key_initialize(processKeyChangeCallback) == KEY_RIGHT) { /* Right key is pressed on power up, clear all NV */ Csf_clearAllNVItems(); } /* Initialize the LCD */ Board_LCD_open(); LCD_WRITE_STRING("TI Collector", 1); #if !defined(AUTO_START) LCD_WRITE_STRING("Waiting...", 2); #endif /* AUTO_START */ Board_Led_initialize(); #if defined(DeviceFamily_CC13X0) || defined(DeviceFamily_CC13X2) Board_Gpio_initialize(); #endif #if defined(MT_CSF) { uint8_t resetReseason = 0; if(pNV != NULL) { if(pNV->readItem != NULL) { /* Attempt to retrieve reason for the reset */ (void)pNV->readItem(nvResetId, 0, 1, &resetReseason); } if(pNV->deleteItem != NULL) { /* Only use this reason once */ (void)pNV->deleteItem(nvResetId); } } /* Start up the MT message handler */ MTCSF_init(resetReseason); /* Did we reset because of assert? */ if(resetReseason > 0) { LCD_WRITE_STRING("Restarting...", 2); /* Tell the collector to restart */ Csf_events |= CSF_KEY_EVENT; Csf_keys |= KEY_LEFT; } } #endif } /*! The application must call this function periodically to process any Csf_events that this module needs to process. Public function defined in csf.h */ void Csf_processEvents(void) { /* Did a key press occur? */ if(Csf_events & CSF_KEY_EVENT) { #ifdef FEATURE_SECURE_COMMISSIONING /* No Key is accepted during CM Process*/ if(SM_Last_State != SM_CM_InProgress) #endif { /* LaunchPad only supports KEY_LEFT and KEY_RIGHT */ if(Csf_keys & KEY_LEFT) { #if !defined(AUTO_START) /* Process the Left Key */ if(started == false) { LCD_WRITE_STRING("Starting...", 2); /* Tell the collector to start */ Util_setEvent(&Collector_events, COLLECTOR_START_EVT); } else #endif /* AUTO_START */ { #if defined(TEST_REMOVE_DEVICE) /* Remove the first device found in the device list. Nobody would do something like this, it's just and example on the use of the device list, remove function and the black list. */ removeTheFirstDevice(); #else /* Send a Toggle LED request to the first device in the device list */ ApiMac_sAddr_t firstDev; firstDev.addr.shortAddr = getTheFirstDevice(); if(firstDev.addr.shortAddr != CSF_INVALID_SHORT_ADDR) { firstDev.addrMode = ApiMac_addrType_short; Collector_sendToggleLedRequest(&firstDev); } #endif } } if(Csf_keys & KEY_RIGHT) { uint32_t duration; #ifdef FEATURE_SECURE_COMMISSIONING if(fCommissionRequired == TRUE) { LCD_WRITE_STRING("PermitJoin blocked", 3); } else #endif { /* Toggle the permit joining */ if (permitJoining == true) { permitJoining = false; duration = 0; LCD_WRITE_STRING("PermitJoin-OFF", 3); } else { permitJoining = true; duration = 0xFFFFFFFF; LCD_WRITE_STRING("PermitJoin-ON ", 3); } /* Set permit joining */ Cllc_setJoinPermit(duration); } } #if defined(FEATURE_OAD) if(Csf_keys & KEY_LEFT && Csf_keys & KEY_RIGHT) { if(hUart != NULL) { UART_close(hUart); } OAD_markSwitch(); } #endif /* FEATURE_OAD */ } /* Clear the key press indication */ Csf_keys = 0; /* Clear the event */ Util_clearEvent(&Csf_events, CSF_KEY_EVENT); } #if defined(MT_CSF) MTCSF_displayStatistics(); #endif } /*! The application calls this function to retrieve the stored network information. Public function defined in csf.h */ bool Csf_getNetworkInformation(Llc_netInfo_t *pInfo) { if((pNV != NULL) && (pNV->readItem != NULL) && (pInfo != NULL)) { NVINTF_itemID_t id; /* Setup NV ID */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_NETWORK_INFO_ID; id.subID = 0; /* Read Network Information from NV */ if(pNV->readItem(id, 0, sizeof(Llc_netInfo_t), pInfo) == NVINTF_SUCCESS) { return(true); } } return(false); } /*! The application calls this function to indicate that it has started or restored the device in a network Public function defined in csf.h */ void Csf_networkUpdate(bool restored, Llc_netInfo_t *pNetworkInfo) { /* check for valid structure ponter, ignore if not */ if(pNetworkInfo != NULL) { if((pNV != NULL) && (pNV->writeItem != NULL)) { NVINTF_itemID_t id; /* Setup NV ID */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_NETWORK_INFO_ID; id.subID = 0; /* Write the NV item */ pNV->writeItem(id, sizeof(Llc_netInfo_t), pNetworkInfo); } started = true; if(restored == false) { LCD_WRITE_STRING("Started", 2); } else { LCD_WRITE_STRING("Restarted", 2); #ifdef FEATURE_SECURE_COMMISSIONING LCD_WRITE_STRING("Key Recovery Mode", 2); #endif } if(pNetworkInfo->fh == false) { LCD_WRITE_STRING_VALUE("Channel: ", pNetworkInfo->channel, 10, 3); } else { LCD_WRITE_STRING("Freq. Hopping", 3); } Board_Led_control(board_led_type_LED1, board_led_state_ON); #if defined(MT_CSF) MTCSF_networkUpdateIndCB(); #endif } } /*! The application calls this function to indicate that a device has joined the network. Public function defined in csf.h */ ApiMac_assocStatus_t Csf_deviceUpdate(ApiMac_deviceDescriptor_t *pDevInfo, ApiMac_capabilityInfo_t *pCapInfo) { ApiMac_assocStatus_t status = ApiMac_assocStatus_success; ApiMac_sAddr_t shortAddr; ApiMac_sAddr_t extAddr; /* flag which will be updated based on if the device joining is a new device or already existing one */ bool newDevice; shortAddr.addrMode = ApiMac_addrType_short; shortAddr.addr.shortAddr = pDevInfo->shortAddress; extAddr.addrMode = ApiMac_addrType_extended; memcpy(&extAddr.addr.extAddr, &pDevInfo->extAddress, APIMAC_SADDR_EXT_LEN); /* Is the device in the black list? */ if((findBlackListIndex(&shortAddr) >= 0) || (findBlackListIndex(&extAddr) >= 0)) { /* Denied */ status = ApiMac_assocStatus_panAccessDenied; LCD_WRITE_STRING_VALUE("Denied: 0x", pDevInfo->shortAddress, 16, 4); } else { /* Save the device information */ Llc_deviceListItem_t dev; memcpy(&dev.devInfo, pDevInfo, sizeof(ApiMac_deviceDescriptor_t)); memcpy(&dev.capInfo, pCapInfo, sizeof(ApiMac_capabilityInfo_t)); dev.rxFrameCounter = 0; if(addDeviceListItem(&dev, &newDevice) == false) { #ifdef NV_RESTORE status = ApiMac_assocStatus_panAtCapacity; LCD_WRITE_STRING_VALUE("Failed: 0x", pDevInfo->shortAddress, 16, 4); #else status = ApiMac_assocStatus_success; LCD_WRITE_STRING_VALUE("Joined: 0x", pDevInfo->shortAddress, 16, 4); #endif } else if (true == newDevice) { LCD_WRITE_STRING_VALUE("Joined: 0x", pDevInfo->shortAddress, 16, 4); } else { LCD_WRITE_STRING_VALUE("Re-Joined: 0x", pDevInfo->shortAddress, 16, 4); } } #if defined(MT_CSF) MTCSF_deviceUpdateIndCB(pDevInfo, pCapInfo); #endif /* Return the status of the joining device */ return (status); } /*! The application calls this function to indicate that a device is no longer active in the network. Public function defined in csf.h */ void Csf_deviceNotActiveUpdate(ApiMac_deviceDescriptor_t *pDevInfo, bool timeout) { LCD_WRITE_STRING_VALUE("!Responding: 0x", pDevInfo->shortAddress, 16, 5); #if defined(MT_CSF) MTCSF_deviceNotActiveIndCB(pDevInfo, timeout); #endif } /*! The application calls this function to indicate that a device has responded to a Config Request. Public function defined in csf.h */ void Csf_deviceConfigUpdate(ApiMac_sAddr_t *pSrcAddr, int8_t rssi, Smsgs_configRspMsg_t *pMsg) { LCD_WRITE_STRING_VALUE("ConfigRsp: 0x", pSrcAddr->addr.shortAddr, 16, 5); #if defined(MT_CSF) MTCSF_configResponseIndCB(pSrcAddr, rssi, pMsg); #endif } /*! The application calls this function to indicate that a device has reported sensor data. Public function defined in csf.h */ void Csf_deviceSensorDataUpdate(ApiMac_sAddr_t *pSrcAddr, int8_t rssi, Smsgs_sensorMsg_t *pMsg) { Board_Led_toggle(board_led_type_LED2); //LCD_WRITE_STRING_VALUE("Sensor 0x", pSrcAddr->addr.shortAddr, 16, 6); LCD_WRITE_STRING_VALUE("Humidity=", pMsg->humiditySensor.humidity , 10, 6); LCD_WRITE_STRING_VALUE("Temperature=", pMsg->humiditySensor.temp, 10, 6); #if defined(MT_CSF) MTCSF_sensorUpdateIndCB(pSrcAddr, rssi, pMsg); #endif } /*! The application calls this function to toggle an LED. Public function defined in ssf.h */ void Csf_identifyLED(uint16_t identifyTime) { Board_Led_control(board_led_type_LED2, board_led_state_BLINKING); /* Setup timer */ Timer_setTimeout(identifyClkHandle, identifyTime); Timer_start(&identifyClkStruct); } /*! The application calls this function to indicate that a device set a Toggle LED Response message. Public function defined in csf.h */ void Csf_toggleResponseReceived(ApiMac_sAddr_t *pSrcAddr, bool ledState) { #if defined(MT_CSF) uint16_t shortAddr = 0xFFFF; if(pSrcAddr) { if(pSrcAddr->addrMode == ApiMac_addrType_short) { shortAddr = pSrcAddr->addr.shortAddr; } else { /* Convert extended to short addr */ shortAddr = Csf_getDeviceShort(&pSrcAddr->addr.extAddr); } } MTCSF_deviceToggleIndCB(shortAddr, ledState); #endif } /*! The application calls this function to indicate that the Coordinator's state has changed. Public function defined in csf.h */ void Csf_stateChangeUpdate(Cllc_states_t state) { if(started == true) { if(state == Cllc_states_joiningAllowed) { /* Flash LED1 while allowing joining */ Board_Led_control(board_led_type_LED1, board_led_state_BLINKING); } else if(state == Cllc_states_joiningNotAllowed) { /* Don't flash when not allowing joining */ Board_Led_control(board_led_type_LED1, board_led_state_ON); } } /* Save the state to be used later */ savedCllcState = state; #if defined(MT_CSF) MTCSF_stateChangeIndCB(state); #endif } /*! Initialize the tracking clock. Public function defined in csf.h */ void Csf_initializeTrackingClock(void) { /* Initialize the timers needed for this application */ trackingClkHandle = Timer_construct(&trackingClkStruct, processTackingTimeoutCallback, TRACKING_INIT_TIMEOUT_VALUE, 0, false, 0); } /*! Initialize the broadcast cmd clock. Public function defined in csf.h */ void Csf_initializeBroadcastClock(void) { /* Initialize the timers needed for this application */ broadcastClkHandle = Timer_construct(&broadcastClkStruct, processBroadcastTimeoutCallback, TRACKING_INIT_TIMEOUT_VALUE, 0, false, 0); } /*! Initialize the trickle clock. Public function defined in csf.h */ void Csf_initializeTrickleClock(void) { /* Initialize trickle timer */ tricklePAClkHandle = Timer_construct(&tricklePAClkStruct, processPATrickleTimeoutCallback, TRICKLE_TIMEOUT_VALUE, 0, false, 0); tricklePCClkHandle = Timer_construct(&tricklePCClkStruct, processPCTrickleTimeoutCallback, TRICKLE_TIMEOUT_VALUE, 0, false, 0); } /*! Initialize the clock for join permit attribute. Public function defined in csf.h */ void Csf_initializeJoinPermitClock(void) { /* Initialize join permit timer */ joinClkHandle = Timer_construct(&joinClkStruct, processJoinTimeoutCallback, JOIN_TIMEOUT_VALUE, 0, false, 0); } /*! Initialize the clock for config request delay Public function defined in csf.h */ void Csf_initializeConfigClock(void) { /* Initialize join permit timer */ configClkHandle = Timer_construct(&configClkStruct, processConfigTimeoutCallback, CONFIG_TIMEOUT_VALUE, 0, false, 0); } /*! Initialize the clock for identify timeout Public function defined in csf.h */ void Csf_initializeIdentifyClock(void) { /* Initialize join permit timer */ identifyClkHandle = Timer_construct(&identifyClkStruct, processidentifyTimeoutCallback, 10, 0, false, 0); } /*! Set the tracking clock. Public function defined in csf.h */ void Csf_setTrackingClock(uint32_t trackingTime) { /* Stop the Tracking timer */ if(Timer_isActive(&trackingClkStruct) == true) { Timer_stop(&trackingClkStruct); } if(trackingTime) { /* Setup timer */ Timer_setTimeout(trackingClkHandle, trackingTime); Timer_start(&trackingClkStruct); } } /*! Set the broadcast clock. Public function defined in csf.h */ void Csf_setBroadcastClock(uint32_t broadcastTime) { /* Stop the Tracking timer */ if(Timer_isActive(&broadcastClkStruct) == true) { Timer_stop(&broadcastClkStruct); } if(broadcastTime) { /* Setup timer */ Timer_setTimeout(broadcastClkHandle, broadcastTime); Timer_start(&broadcastClkStruct); } } /*! Set the trickle clock. Public function defined in csf.h */ void Csf_setTrickleClock(uint32_t trickleTime, uint8_t frameType) { uint16_t randomNum = 0; uint16_t randomTime = 0; if(trickleTime > 0) { randomNum = ((ApiMac_randomByte() << 8) + ApiMac_randomByte()); randomTime = (trickleTime >> 1) + (randomNum % (trickleTime >> 1)); } if(frameType == ApiMac_wisunAsyncFrame_advertisement) { /* Stop the PA trickle timer */ if(Timer_isActive(&tricklePAClkStruct) == true) { Timer_stop(&tricklePAClkStruct); } if(trickleTime > 0) { /* Setup timer */ Timer_setTimeout(tricklePAClkHandle, randomTime); Timer_start(&tricklePAClkStruct); } } else if(frameType == ApiMac_wisunAsyncFrame_config) { /* Stop the PC trickle timer */ if(Timer_isActive(&tricklePCClkStruct) == true) { Timer_stop(&tricklePCClkStruct); } if(trickleTime > 0) { /* Setup timer */ Timer_setTimeout(tricklePCClkHandle, randomTime); Timer_start(&tricklePCClkStruct); } } } /*! Set the clock join permit attribute. Public function defined in csf.h */ void Csf_setJoinPermitClock(uint32_t joinDuration) { /* Stop the join timer */ if(Timer_isActive(&joinClkStruct) == true) { Timer_stop(&joinClkStruct); } if(joinDuration != 0) { /* Setup timer */ Timer_setTimeout(joinClkHandle, joinDuration); Timer_start(&joinClkStruct); } } /*! Set the clock config request delay. Public function defined in csf.h */ void Csf_setConfigClock(uint32_t delay) { /* Stop the join timer */ if(Timer_isActive(&configClkStruct) == true) { Timer_stop(&configClkStruct); } if(delay != 0) { /* Setup timer */ Timer_setTimeout(configClkHandle, delay); Timer_start(&configClkStruct); } } /*! Read the number of device list items stored Public function defined in csf.h */ uint16_t Csf_getNumDeviceListEntries(void) { uint16_t numEntries = 0; if(pNV != NULL) { NVINTF_itemID_t id; uint8_t stat; /* Setup NV ID for the number of entries in the device list */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ENTRIES_ID; id.subID = 0; /* Read the number of device list items from NV */ stat = pNV->readItem(id, 0, sizeof(uint16_t), &numEntries); if(stat != NVINTF_SUCCESS) { numEntries = 0; } } return (numEntries); } /*! Find the short address from a given extended address Public function defined in csf.h */ uint16_t Csf_getDeviceShort(ApiMac_sAddrExt_t *pExtAddr) { Llc_deviceListItem_t item; ApiMac_sAddr_t devAddr; uint16_t shortAddr = CSF_INVALID_SHORT_ADDR; devAddr.addrMode = ApiMac_addrType_extended; memcpy(&devAddr.addr.extAddr, pExtAddr, sizeof(ApiMac_sAddrExt_t)); if(Csf_getDevice(&devAddr,&item)) { shortAddr = item.devInfo.shortAddress; } return(shortAddr); } /*! Find entry in device list Public function defined in csf.h */ bool Csf_getDevice(ApiMac_sAddr_t *pDevAddr, Llc_deviceListItem_t *pItem) { if((pNV != NULL) && (pItem != NULL)) { uint16_t numEntries; numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; uint8_t stat; int subId = 0; int readItems = 0; /* Setup NV ID for the device list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; while((readItems < numEntries) && (subId < CSF_MAX_DEVICELIST_IDS)) { Llc_deviceListItem_t item; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(Llc_deviceListItem_t), &item); if(stat == NVINTF_SUCCESS) { if(((pDevAddr->addrMode == ApiMac_addrType_short) && (pDevAddr->addr.shortAddr == item.devInfo.shortAddress)) || ((pDevAddr->addrMode == ApiMac_addrType_extended) && (memcmp(&pDevAddr->addr.extAddr, &item.devInfo.extAddress, (APIMAC_SADDR_EXT_LEN)) == 0))) { memcpy(pItem, &item, sizeof(Llc_deviceListItem_t)); return (true); } readItems++; } subId++; } } } return (false); } /*! Find entry in device list Public function defined in csf.h */ bool Csf_getDeviceItem(uint16_t devIndex, Llc_deviceListItem_t *pItem) { if((pNV != NULL) && (pItem != NULL)) { uint16_t numEntries; numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; uint8_t stat; int subId = 0; int readItems = 0; /* Setup NV ID for the device list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; while((readItems < numEntries) && (subId < CSF_MAX_DEVICELIST_IDS)) { Llc_deviceListItem_t item; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(Llc_deviceListItem_t), &item); if(stat == NVINTF_SUCCESS) { if(readItems == devIndex) { memcpy(pItem, &item, sizeof(Llc_deviceListItem_t)); return (true); } readItems++; } subId++; } } } return (false); } /*! Csf implementation for memory allocation Public function defined in csf.h */ void *Csf_malloc(uint16_t size) { #ifdef OSAL_PORT2TIRTOS return OsalPort_malloc(size); #else return(ICall_malloc(size)); #endif } /*! Csf implementation for memory de-allocation Public function defined in csf.h */ void Csf_free(void *ptr) { if(ptr != NULL) { #ifdef OSAL_PORT2TIRTOS OsalPort_free(ptr); #else ICall_free(ptr); #endif } } /*! Update the Frame Counter Public function defined in csf.h */ void Csf_updateFrameCounter(ApiMac_sAddr_t *pDevAddr, uint32_t frameCntr) { if((pNV != NULL) && (pNV->writeItem != NULL)) { if(pDevAddr == NULL) { /* Update this device's frame counter */ if((frameCntr >= (lastSavedCoordinatorFrameCounter + FRAME_COUNTER_SAVE_WINDOW))) { NVINTF_itemID_t id; /* Setup NV ID */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_FRAMECOUNTER_ID; id.subID = 0; /* Write the NV item */ if(pNV->writeItem(id, sizeof(uint32_t), &frameCntr) == NVINTF_SUCCESS) { lastSavedCoordinatorFrameCounter = frameCntr; } } } else { /* Child frame counter update */ Llc_deviceListItem_t devItem; /* Is the device in our database? */ if(Csf_getDevice(pDevAddr, &devItem)) { /* Don't save every update, only save if the new frame counter falls outside the save window. */ if((devItem.rxFrameCounter + FRAME_COUNTER_SAVE_WINDOW) <= frameCntr) { /* Update the frame counter */ devItem.rxFrameCounter = frameCntr; updateDeviceListItem(&devItem); } } } } } /*! Get the Frame Counter Public function defined in csf.h */ bool Csf_getFrameCounter(ApiMac_sAddr_t *pDevAddr, uint32_t *pFrameCntr) { /* Check for valid pointer */ if(pFrameCntr != NULL) { /* A pDevAddr that is null means to get the frame counter for this device */ if(pDevAddr == NULL) { if((pNV != NULL) && (pNV->readItem != NULL)) { NVINTF_itemID_t id; /* Setup NV ID */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_FRAMECOUNTER_ID; id.subID = 0; /* Read Network Information from NV */ if(pNV->readItem(id, 0, sizeof(uint32_t), pFrameCntr) == NVINTF_SUCCESS) { /* Set to the next window */ *pFrameCntr += FRAME_COUNTER_SAVE_WINDOW; return(true); } else { /* Wasn't found, so write 0, so the next time it will be greater than 0 */ uint32_t fc = 0; /* Setup NV ID */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_FRAMECOUNTER_ID; id.subID = 0; /* Write the NV item */ pNV->writeItem(id, sizeof(uint32_t), &fc); } } } *pFrameCntr = 0; } return (false); } /*! Delete an entry from the device list Public function defined in csf.h */ void Csf_removeDeviceListItem(ApiMac_sAddrExt_t *pAddr) { if((pNV != NULL) && (pNV->deleteItem != NULL)) { int index; /* Does the item exist? */ index = findDeviceListIndex(pAddr); if(index != DEVICE_INDEX_NOT_FOUND) { uint8_t stat; NVINTF_itemID_t id; /* Setup NV ID for the device list record */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; id.subID = (uint16_t)index; stat = pNV->deleteItem(id); if(stat == NVINTF_SUCCESS) { /* Update the number of entries */ uint16_t numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { numEntries--; saveNumDeviceListEntries(numEntries); } } } } } /*! Assert Indication Public function defined in csf.h */ void Csf_assertInd(uint8_t reason) { #if defined(MT_CSF) if((pNV != NULL) && (pNV->writeItem != NULL)) { /* Attempt to save reason to read after reset */ (void)pNV->writeItem(nvResetId, 1, &reason); } #endif } /*! Clear all the NV Items Public function defined in csf.h */ void Csf_clearAllNVItems(void) { #ifdef ONE_PAGE_NV if((pNV != NULL) && (pNV->deleteItem != NULL)) { NVINTF_itemID_t id; /* Clear all information */ id.systemID = 0xFF; id.itemID = 0xFFFF; id.subID = 0xFFFF; pNV->deleteItem(id); } #else if((pNV != NULL) && (pNV->deleteItem != NULL)) { NVINTF_itemID_t id; uint16_t entries; /* Clear Network Information */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_NETWORK_INFO_ID; id.subID = 0; pNV->deleteItem(id); /* Clear the black list entries number */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ENTRIES_ID; id.subID = 0; pNV->deleteItem(id); /* Clear the black list entries. Brute force through every possible subID, if it doesn't exist that's fine, it will fail in deleteItem. */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ID; for(entries = 0; entries < CSF_MAX_BLACKLIST_IDS; entries++) { id.subID = entries; pNV->deleteItem(id); } /* Clear the device list entries number */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ENTRIES_ID; id.subID = 0; pNV->deleteItem(id); /* Clear the device list entries. Brute force through every possible subID, if it doesn't exist that's fine, it will fail in deleteItem. */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; for(entries = 0; entries < CSF_MAX_DEVICELIST_IDS; entries++) { id.subID = entries; pNV->deleteItem(id); } /* Clear the device tx frame counter */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_FRAMECOUNTER_ID; id.subID = 0; pNV->deleteItem(id); } #endif } /*! Add an entry into the black list Public function defined in csf.h */ bool Csf_addBlackListItem(ApiMac_sAddr_t *pAddr) { bool retVal = false; if((pNV != NULL) && (pAddr != NULL) && (pAddr->addrMode != ApiMac_addrType_none)) { if(findBlackListIndex(pAddr)) { retVal = true; } else { uint8_t stat; NVINTF_itemID_t id; uint16_t numEntries = getNumBlackListEntries(); /* Check the maximum size */ if(numEntries < CSF_MAX_BLACKLIST_ENTRIES) { /* Setup NV ID for the black list record */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ID; id.subID = (uint16_t)findUnusedBlackListIndex(); /* write the black list record */ stat = pNV->writeItem(id, sizeof(ApiMac_sAddr_t), pAddr); if(stat == NVINTF_SUCCESS) { /* Update the number of entries */ numEntries++; saveNumBlackListEntries(numEntries); retVal = true; } } } } return (retVal); } /*! Check if config timer is active Public function defined in csf.h */ bool Csf_isConfigTimerActive(void) { return(Timer_isActive(&configClkStruct)); } /*! Check if tracking timer is active Public function defined in csf.h */ bool Csf_isTrackingTimerActive(void) { return(Timer_isActive(&trackingClkStruct)); } /****************************************************************************** Local Functions *****************************************************************************/ /*! * @brief Tracking timeout handler function. * * @param a0 - ignored */ static void processTackingTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ Util_setEvent(&Collector_events, COLLECTOR_TRACKING_TIMEOUT_EVT); /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Tracking timeout handler function. * * @param a0 - ignored */ static void processBroadcastTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ Util_setEvent(&Collector_events, COLLECTOR_BROADCAST_TIMEOUT_EVT); /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Join permit timeout handler function. * * @param a0 - ignored */ static void processJoinTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ Util_setEvent(&Cllc_events, CLLC_JOIN_EVT); /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Config delay timeout handler function. * * @param a0 - ignored */ static void processConfigTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ Util_setEvent(&Collector_events, COLLECTOR_CONFIG_EVT); /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Identify timeout handler function. * * @param a0 - ignored */ static void processidentifyTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ /* Stop LED blinking - we can write to GPIO in SWI */ Board_Led_control(board_led_type_LED2, board_led_state_OFF); } /*! * @brief Trickle timeout handler function for PA . * * @param a0 - ignored */ static void processPATrickleTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ Util_setEvent(&Cllc_events, CLLC_PA_EVT); /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Trickle timeout handler function for PC. * * @param a0 - ignored */ static void processPCTrickleTimeoutCallback(UArg a0) { (void)a0; /* Parameter is not used */ Util_setEvent(&Cllc_events, CLLC_PC_EVT); /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Key event handler function * * @param keysPressed - Csf_keys that are pressed */ static void processKeyChangeCallback(uint8_t keysPressed) { Csf_keys = keysPressed; Csf_events |= CSF_KEY_EVENT; /* Wake up the application thread when it waits for clock event */ Semaphore_post(collectorSem); } /*! * @brief Add an entry into the device list * * @param pItem - pointer to the device list entry * @param pNewDevice - pointer to a flag which will be updated * based on if the sensor joining is already assoc with * the collector or freshly joining the network * @return true if added or already existed, false if problem */ static bool addDeviceListItem(Llc_deviceListItem_t *pItem, bool *pNewDevice) { bool retVal = false; /* By default, set this flag to true; will be updated - if device already found in the list*/ *pNewDevice = true; if((pNV != NULL) && (pItem != NULL)) { if(findDeviceListIndex(&pItem->devInfo.extAddress) != DEVICE_INDEX_NOT_FOUND) { retVal = true; /* Not a new device; already exists */ *pNewDevice = false; } else { uint8_t stat; NVINTF_itemID_t id; uint16_t numEntries = Csf_getNumDeviceListEntries(); /* Check the maximum size */ if(numEntries < CSF_MAX_DEVICELIST_ENTRIES) { /* Setup NV ID for the device list record */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; id.subID = (uint16_t)findUnusedDeviceListIndex(); /* write the device list record */ stat = pNV->writeItem(id, sizeof(Llc_deviceListItem_t), pItem); if(stat == NVINTF_SUCCESS) { /* Update the number of entries */ numEntries++; saveNumDeviceListEntries(numEntries); retVal = true; } } } } return (retVal); } /*! * @brief Update an entry in the device list * * @param pItem - pointer to the device list entry */ static void updateDeviceListItem(Llc_deviceListItem_t *pItem) { if((pNV != NULL) && (pItem != NULL)) { int idx; idx = findDeviceListIndex(&pItem->devInfo.extAddress); if(idx != DEVICE_INDEX_NOT_FOUND) { NVINTF_itemID_t id; /* Setup NV ID for the device list record */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; id.subID = (uint16_t)idx; /* write the device list record */ pNV->writeItem(id, sizeof(Llc_deviceListItem_t), pItem); } } } /*! * @brief Find entry in device list * * @param pAddr - address to of device to find * * @return sub index into the device list, -1 (DEVICE_INDEX_NOT_FOUND) * if not found */ static int findDeviceListIndex(ApiMac_sAddrExt_t *pAddr) { if((pNV != NULL) && (pAddr != NULL)) { uint16_t numEntries; numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; uint8_t stat; int subId = 0; int readItems = 0; /* Setup NV ID for the device list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; while((readItems < numEntries) && (subId < CSF_MAX_DEVICELIST_IDS)) { Llc_deviceListItem_t item; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(Llc_deviceListItem_t), &item); if(stat == NVINTF_SUCCESS) { /* Is the address the same */ if(memcmp(pAddr, &item.devInfo.extAddress, (APIMAC_SADDR_EXT_LEN)) == 0) { return (subId); } readItems++; } subId++; } } } return (DEVICE_INDEX_NOT_FOUND); } /*! * @brief Find an unused device list index * * @return index that is not in use */ static int findUnusedDeviceListIndex(void) { int subId = 0; if(pNV != NULL) { uint16_t numEntries; numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; int readItems = 0; /* Setup NV ID for the device list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; while((readItems < numEntries) && (subId < CSF_MAX_DEVICELIST_IDS)) { Llc_deviceListItem_t item; uint8_t stat; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(Llc_deviceListItem_t), &item); if(stat == NVINTF_NOTFOUND) { /* Use this sub id */ break; } else if(stat == NVINTF_SUCCESS) { readItems++; } subId++; } } } return (subId); } /*! * @brief Read the number of device list items stored * * @param numEntries - number of entries in the device list */ static void saveNumDeviceListEntries(uint16_t numEntries) { if(pNV != NULL) { NVINTF_itemID_t id; /* Setup NV ID for the number of entries in the device list */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ENTRIES_ID; id.subID = 0; /* Read the number of device list items from NV */ pNV->writeItem(id, sizeof(uint16_t), &numEntries); } } /*! * @brief Find entry in black list * * @param pAddr - address to add into the black list * * @return sub index into the blacklist, -1 if not found */ static int findBlackListIndex(ApiMac_sAddr_t *pAddr) { if((pNV != NULL) && (pAddr != NULL) && (pAddr->addrMode != ApiMac_addrType_none)) { uint16_t numEntries; numEntries = getNumBlackListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; uint8_t stat; int subId = 0; int readItems = 0; /* Setup NV ID for the black list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ID; while((readItems < numEntries) && (subId < CSF_MAX_BLACKLIST_IDS)) { ApiMac_sAddr_t item; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(ApiMac_sAddr_t), &item); if(stat == NVINTF_SUCCESS) { if(pAddr->addrMode == item.addrMode) { /* Is the address the same */ if(((pAddr->addrMode == ApiMac_addrType_short) && (pAddr->addr.shortAddr == item.addr.shortAddr)) || ((pAddr->addrMode == ApiMac_addrType_extended) && (memcmp(&pAddr->addr.extAddr, &item.addr.extAddr, APIMAC_SADDR_EXT_LEN) == 0))) { return (subId); } } readItems++; } subId++; } } } return (-1); } /*! * @brief Find an unused blacklist index * * @return index that is not in use */ static int findUnusedBlackListIndex(void) { int subId = 0; if(pNV != NULL) { uint16_t numEntries; numEntries = getNumBlackListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; int readItems = 0; /* Setup NV ID for the black list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ID; while((readItems < numEntries) && (subId < CSF_MAX_BLACKLIST_IDS)) { ApiMac_sAddr_t item; uint8_t stat; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(ApiMac_sAddr_t), &item); if(stat == NVINTF_NOTFOUND) { /* Use this sub id */ break; } else if(stat == NVINTF_SUCCESS) { readItems++; } subId++; } } } return (subId); } /*! * @brief Read the number of black list items stored * * @return number of entries in the black list */ static uint16_t getNumBlackListEntries(void) { uint16_t numEntries = 0; if(pNV != NULL) { NVINTF_itemID_t id; uint8_t stat; /* Setup NV ID for the number of entries in the black list */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ENTRIES_ID; id.subID = 0; /* Read the number of black list items from NV */ stat = pNV->readItem(id, 0, sizeof(uint16_t), &numEntries); if(stat != NVINTF_SUCCESS) { numEntries = 0; } } return (numEntries); } /*! * @brief Read the number of black list items stored * * @param numEntries - number of entries in the black list */ static void saveNumBlackListEntries(uint16_t numEntries) { if(pNV != NULL) { NVINTF_itemID_t id; /* Setup NV ID for the number of entries in the black list */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ENTRIES_ID; id.subID = 0; /* Read the number of black list items from NV */ pNV->writeItem(id, sizeof(uint16_t), &numEntries); } } /*! * @brief Delete an address from the black list * * @param pAddr - address to remove from black list. */ void removeBlackListItem(ApiMac_sAddr_t *pAddr) { if(pNV != NULL) { int index; /* Does the item exist? */ index = findBlackListIndex(pAddr); if(index > 0) { uint8_t stat; NVINTF_itemID_t id; /* Setup NV ID for the black list record */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_BLACKLIST_ID; id.subID = (uint16_t)index; stat = pNV->deleteItem(id); if(stat == NVINTF_SUCCESS) { /* Update the number of entries */ uint16_t numEntries = getNumBlackListEntries(); if(numEntries > 0) { numEntries--; saveNumBlackListEntries(numEntries); } } } } } #if defined(TEST_REMOVE_DEVICE) /*! * @brief This is an example function on how to remove a device * from this network. */ static void removeTheFirstDevice(void) { if(pNV != NULL) { uint16_t numEntries; numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; uint16_t subId = 0; /* Setup NV ID for the device list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; while(subId < CSF_MAX_DEVICELIST_IDS) { Llc_deviceListItem_t item; uint8_t stat; id.subID = (uint16_t)subId; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(Llc_deviceListItem_t), &item); if(stat == NVINTF_SUCCESS) { /* Found the first device in the list */ ApiMac_sAddr_t addr; /* Send a disassociate to the device */ Cllc_sendDisassociationRequest(item.devInfo.shortAddress, item.capInfo.rxOnWhenIdle); /* remove device from the NV list */ Cllc_removeDevice(&item.devInfo.extAddress); /* Remove it from the Device list */ Csf_removeDeviceListItem(&item.devInfo.extAddress); /* Add the device to the black list so it can't join again */ addr.addrMode = ApiMac_addrType_extended; memcpy(&addr.addr.extAddr, &item.devInfo.extAddress, (APIMAC_SADDR_EXT_LEN)); Csf_addBlackListItem(&addr); break; } subId++; } } } } #else /*! * @brief Retrieve the first device's short address * * @return short address or 0xFFFF if not found */ static uint16_t getTheFirstDevice(void) { uint16_t found = CSF_INVALID_SHORT_ADDR; if(pNV != NULL) { uint16_t numEntries; numEntries = Csf_getNumDeviceListEntries(); if(numEntries > 0) { NVINTF_itemID_t id; /* Setup NV ID for the device list records */ id.systemID = NVINTF_SYSID_APP; id.itemID = CSF_NV_DEVICELIST_ID; id.subID = 0; while(id.subID < CSF_MAX_DEVICELIST_IDS) { Llc_deviceListItem_t item; uint8_t stat; /* Read Network Information from NV */ stat = pNV->readItem(id, 0, sizeof(Llc_deviceListItem_t), &item); if(stat == NVINTF_SUCCESS) { found = item.devInfo.shortAddress; break; } id.subID++; } } } return(found); } #endif /*! * @brief Handles printing that the orphaned device joined back * * @return none */ void Csf_IndicateOrphanReJoin(uint16_t shortAddr) { LCD_WRITE_STRING_VALUE("Orphaned Sensor Re-Joined: 0x", shortAddr, 16, 4); }

/****************************************************************************** @file sensor.c @brief TIMAC 2.0 Sensor Example Application Group: WCS LPC Target Device: cc13x0 ****************************************************************************** Copyright (c) 2016-2019, Texas Instruments Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Texas Instruments Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *****************************************************************************/ /****************************************************************************** Includes *****************************************************************************/ #include <string.h> #include <stdint.h> #include "mac_util.h" #include "api_mac.h" #include "jdllc.h" #include "ssf.h" #include "smsgs.h" #include "sensor.h" #include "config.h" #include "board_led.h" #include "board_lcd.h" #include <ti/drivers/I2C.h> #include <ti/drivers/GPIO.h> #define TMP116_DIE_TEMP 0xE3 #define Si7021_ADDR 0x40 #if defined(HUMIDITY_SENSOR) I2C_Handle i2c; I2C_Params i2cParams; I2C_Transaction i2cTransaction; float temperature; double temper; float humidity; double humi; uint8_t txBuffer[1]; uint8_t rxBuffer[2]; #endif #ifdef FEATURE_NATIVE_OAD #include "oad_client.h" #endif /* FEATURE_NATIVE_OAD */ #ifdef OSAL_PORT2TIRTOS #include <ti/sysbios/knl/Clock.h> #else #include "icall.h" #endif #ifdef FEATURE_SECURE_COMMISSIONING #include "sm_ti154.h" #endif /****************************************************************************** Constants and definitions *****************************************************************************/ #if !defined(CONFIG_AUTO_START) #if defined(AUTO_START) #define CONFIG_AUTO_START 1 #else #define CONFIG_AUTO_START 0 #endif #endif /* default MSDU Handle rollover */ #define MSDU_HANDLE_MAX 0x1F /* App marker in MSDU handle */ #define APP_MARKER_MSDU_HANDLE 0x80 /* App Message Tracking Mask */ #define APP_MASK_MSDU_HANDLE 0x60 /* App Sensor Data marker for the MSDU handle */ #define APP_SENSOR_MSDU_HANDLE 0x40 /* App tracking response marker for the MSDU handle */ #define APP_TRACKRSP_MSDU_HANDLE 0x20 /* App config response marker for the MSDU handle */ #define APP_CONFIGRSP_MSDU_HANDLE 0x60 /* Reporting Interval Min and Max (in milliseconds) */ #define MIN_REPORTING_INTERVAL 1000 #define MAX_REPORTING_INTERVAL 360000 /* Polling Interval Min and Max (in milliseconds) */ #define MIN_POLLING_INTERVAL 1000 //100 #define MAX_POLLING_INTERVAL 10000 /* Blink Time for Identify LED Request (in milliseconds) */ #define IDENTIFY_LED_TIME 1000 /* Inter packet interval in certification test mode */ #if CERTIFICATION_TEST_MODE #if ((CONFIG_PHY_ID >= APIMAC_MRFSK_STD_PHY_ID_BEGIN) && (CONFIG_PHY_ID <= APIMAC_MRFSK_GENERIC_PHY_ID_BEGIN)) /*! Regular Mode */ #define SENSOR_TEST_RAMP_DATA_SIZE 75 #define CERT_MODE_INTER_PKT_INTERVAL 50 #elif ((CONFIG_PHY_ID >= APIMAC_MRFSK_GENERIC_PHY_ID_BEGIN + 1) && (CONFIG_PHY_ID <= APIMAC_MRFSK_GENERIC_PHY_ID_END)) /*! LRM Mode */ #define SENSOR_TEST_RAMP_DATA_SIZE 20 #define CERT_MODE_INTER_PKT_INTERVAL 300 #else #error "PHY ID is wrong." #endif #endif /****************************************************************************** Global variables *****************************************************************************/ /* Task pending events */ uint16_t Sensor_events = 0; /*! Sensor statistics */ Smsgs_msgStatsField_t Sensor_msgStats = { 0 }; extern bool initBroadcastMsg; extern bool parentFound; #ifdef POWER_MEAS /*! Power Meas Stats fields */ Smsgs_powerMeastatsField_t Sensor_pwrMeasStats = { 0 }; #endif /****************************************************************************** Local variables *****************************************************************************/ static void *sem; /*! Rejoined flag */ static bool rejoining = false; /*! Collector's address */ static ApiMac_sAddr_t collectorAddr = {0}; /* Join Time Ticks (used for average join time calculations) */ static uint_fast32_t joinTimeTicks = 0; /* End to end delay statistics timestamp */ static uint32_t startSensorMsgTimeStamp = 0; /*! Device's Outgoing MSDU Handle values */ STATIC uint8_t deviceTxMsduHandle = 0; STATIC Smsgs_configReqMsg_t configSettings; #if !defined(OAD_IMG_A) /*! Temp Sensor field - valid only if Smsgs_dataFields_tempSensor is set in frameControl. */ STATIC Smsgs_tempSensorField_t tempSensor = { 0 }; /*! Light Sensor field - valid only if Smsgs_dataFields_lightSensor is set in frameControl. */ STATIC Smsgs_lightSensorField_t lightSensor = { 0 }; /*! Humidity Sensor field - valid only if Smsgs_dataFields_humiditySensor is set in frameControl. */ STATIC Smsgs_humiditySensorField_t humiditySensor = { 0 }; #endif //OAD_IMG_A STATIC Llc_netInfo_t parentInfo = {0}; STATIC uint16_t lastRcvdBroadcastMsgId = 0; #ifdef FEATURE_SECURE_COMMISSIONING /* variable to store the current setting of auto Request Pib attribute * before it gets modified by SM module, in beacon mode */ static bool currAutoReq = 0; #endif /* FEATURE_SECURE_COMMISSIONING */ #ifdef OAD_IMG_A static bool Oad_hasSentResetRsp = false; #endif /* OAD_IMG_A */ /****************************************************************************** Local function prototypes *****************************************************************************/ static void initializeClocks(void); static void dataCnfCB(ApiMac_mcpsDataCnf_t *pDataCnf); static void dataIndCB(ApiMac_mcpsDataInd_t *pDataInd); static uint8_t getMsduHandle(Smsgs_cmdIds_t msgType); #if !defined(OAD_IMG_A) static void processSensorMsgEvt(void); static bool sendSensorMessage(ApiMac_sAddr_t *pDstAddr, Smsgs_sensorMsg_t *pMsg); static void readSensors(void); #endif //OAD_IMG_A #if SENSOR_TEST_RAMP_DATA_SIZE static void processSensorRampMsgEvt(void); #endif static void processConfigRequest(ApiMac_mcpsDataInd_t *pDataInd); static void processBroadcastCtrlMsg(ApiMac_mcpsDataInd_t *pDataInd); static bool sendConfigRsp(ApiMac_sAddr_t *pDstAddr, Smsgs_configRspMsg_t *pMsg); static uint16_t validateFrameControl(uint16_t frameControl); static void jdllcJoinedCb(ApiMac_deviceDescriptor_t *pDevInfo, Llc_netInfo_t *pStartedInfo); static void jdllcDisassocIndCb(ApiMac_sAddrExt_t *extAddress, ApiMac_disassocateReason_t reason); static void jdllcDisassocCnfCb(ApiMac_sAddrExt_t *extAddress, ApiMac_status_t status); static void jdllcStateChangeCb(Jdllc_states_t state); #ifdef FEATURE_SECURE_COMMISSIONING /* Security Manager callback functions */ static void smFailCMProcessCb(ApiMac_deviceDescriptor_t *devInfo, bool rxOnIdle, bool keyRefreshment); static void smSuccessCMProcessCb(ApiMac_deviceDescriptor_t *devInfo, bool keyRefreshment); #endif /****************************************************************************** Callback tables *****************************************************************************/ /*! API MAC Callback table */ STATIC ApiMac_callbacks_t Sensor_macCallbacks = { /*! Associate Indicated callback */ NULL, /*! Associate Confirmation callback */ NULL, /*! Disassociate Indication callback */ NULL, /*! Disassociate Confirmation callback */ NULL, /*! Beacon Notify Indication callback */ NULL, /*! Orphan Indication callback */ NULL, /*! Scan Confirmation callback */ NULL, /*! Start Confirmation callback */ NULL, /*! Sync Loss Indication callback */ NULL, /*! Poll Confirm callback */ NULL, /*! Comm Status Indication callback */ NULL, /*! Poll Indication Callback */ NULL, /*! Data Confirmation callback */ dataCnfCB, /*! Data Indication callback */ dataIndCB, /*! Purge Confirm callback */ NULL, /*! WiSUN Async Indication callback */ NULL, /*! WiSUN Async Confirmation callback */ NULL, /*! Unprocessed message callback */ NULL }; STATIC Jdllc_callbacks_t jdllcCallbacks = { /*! Network Joined Indication callback */ jdllcJoinedCb, /* Disassociation Indication callback */ jdllcDisassocIndCb, /* Disassociation Confirm callback */ jdllcDisassocCnfCb, /*! State Changed indication callback */ jdllcStateChangeCb }; #ifdef FEATURE_SECURE_COMMISSIONING STATIC SM_callbacks_t SMCallbacks = { /*! Security authentication failed callback */ smFailCMProcessCb, /* Security authentication successful callback */ smSuccessCMProcessCb }; #endif /****************************************************************************** Public Functions *****************************************************************************/ /*! Initialize this application. Public function defined in sensor.h */ #ifdef OSAL_PORT2TIRTOS void Sensor_init(uint8_t macTaskId) #else void Sensor_init(void) #endif { uint32_t frameCounter = 0; /* Initialize the sensor's structures */ memset(&configSettings, 0, sizeof(Smsgs_configReqMsg_t)); #if defined(TEMP_SENSOR) configSettings.frameControl |= Smsgs_dataFields_tempSensor; #endif #if defined(LIGHT_SENSOR) configSettings.frameControl |= Smsgs_dataFields_lightSensor; #endif #if defined(HUMIDITY_SENSOR) I2C_init(); GPIO_init(); /* Configure the LED and if applicable, the TMP116_EN pin */ /*GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW); #ifdef Board_GPIO_TMP116_EN GPIO_setConfig(Board_GPIO_TMP116_EN, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_HIGH); // sleep(1); #endif*/ configSettings.frameControl |= Smsgs_dataFields_humiditySensor; #endif configSettings.frameControl |= Smsgs_dataFields_msgStats; configSettings.frameControl |= Smsgs_dataFields_configSettings; if(!CERTIFICATION_TEST_MODE) { configSettings.reportingInterval = CONFIG_REPORTING_INTERVAL; } else { /* start back to back data transmission at the earliest */ configSettings.reportingInterval = 100; } configSettings.pollingInterval = CONFIG_POLLING_INTERVAL; /* Initialize the MAC */ #ifdef OSAL_PORT2TIRTOS sem = ApiMac_init(macTaskId, CONFIG_FH_ENABLE); #else sem = ApiMac_init(CONFIG_FH_ENABLE); #endif /* Initialize the Joining Device Logical Link Controller */ Jdllc_init(&Sensor_macCallbacks, &jdllcCallbacks); /* Register the MAC Callbacks */ ApiMac_registerCallbacks(&Sensor_macCallbacks); /* Initialize the platform specific functions */ Ssf_init(sem); #ifdef FEATURE_SECURE_COMMISSIONING /* Intialize the security manager and register callbacks */ SM_init(); SM_registerCallback(&SMCallbacks); #endif /* FEATURE_SECURE_COMMISSIONING */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_phyCurrentDescriptorId, (uint8_t)CONFIG_PHY_ID); ApiMac_mlmeSetReqUint8(ApiMac_attribute_channelPage, (uint8_t)CONFIG_CHANNEL_PAGE); Ssf_getFrameCounter(NULL, &frameCounter); #ifdef FEATURE_MAC_SECURITY /* Initialize the MAC Security */ Jdllc_securityInit(frameCounter); #endif /* FEATURE_MAC_SECURITY */ /* Set the transmit power */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_phyTransmitPowerSigned, (uint8_t)CONFIG_TRANSMIT_POWER); /* Set Min BE */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_backoffExponent, (uint8_t)CONFIG_MIN_BE); /* Set Max BE */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_maxBackoffExponent, (uint8_t)CONFIG_MAX_BE); /* Set MAC MAX CSMA Backoffs */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_maxCsmaBackoffs, (uint8_t)CONFIG_MAC_MAX_CSMA_BACKOFFS); /* Set MAC MAX Frame Retries */ ApiMac_mlmeSetReqUint8(ApiMac_attribute_maxFrameRetries, (uint8_t)CONFIG_MAX_RETRIES); #ifdef FCS_TYPE16 /* Set the fcs type */ ApiMac_mlmeSetReqBool(ApiMac_attribute_fcsType, (bool)1); #endif /* Initialize the app clocks */ initializeClocks(); if(CONFIG_AUTO_START) { /* Start the device */ Util_setEvent(&Sensor_events, SENSOR_START_EVT); } } /*! Application task processing. Public function defined in sensor.h */ void Sensor_process(void) { /* Start the collector device in the network */ if(Sensor_events & SENSOR_START_EVT) { ApiMac_deviceDescriptor_t devInfo; Llc_netInfo_t parentInfo; if(Ssf_getNetworkInfo(&devInfo, &parentInfo ) == true) { Ssf_configSettings_t configInfo; #ifdef FEATURE_MAC_SECURITY ApiMac_status_t stat; #endif /* FEATURE_MAC_SECURITY */ /* Do we have config settings? */ if(Ssf_getConfigInfo(&configInfo) == true) { /* Save the config information */ configSettings.frameControl = configInfo.frameControl; configSettings.reportingInterval = configInfo.reportingInterval; configSettings.pollingInterval = configInfo.pollingInterval; /* Update the polling interval in the LLC */ Jdllc_setPollRate(configSettings.pollingInterval); } /* Initially, setup the parent as the collector */ if(parentInfo.fh == true && CONFIG_RX_ON_IDLE) { collectorAddr.addrMode = ApiMac_addrType_extended; memcpy(&collectorAddr.addr.extAddr, parentInfo.devInfo.extAddress, APIMAC_SADDR_EXT_LEN); } else { collectorAddr.addrMode = ApiMac_addrType_short; collectorAddr.addr.shortAddr = parentInfo.devInfo.shortAddress; } #ifdef FEATURE_MAC_SECURITY /* Put the parent in the security device list */ stat = Jdllc_addSecDevice(parentInfo.devInfo.panID, parentInfo.devInfo.shortAddress, &parentInfo.devInfo.extAddress, 0); if(stat != ApiMac_status_success) { Ssf_displayError("Auth Error: 0x", (uint8_t)stat); } #endif /* FEATURE_MAC_SECURITY */ #ifdef FEATURE_SECURE_COMMISSIONING if(!CONFIG_FH_ENABLE) { nvDeviceKeyInfo_t devKeyInfo; SM_seedKey_Entry_t * pSeedKeyEnty; if(Ssf_getDeviceKeyInfo(&devKeyInfo) == TRUE) { /* Update the seedKeyTable and MAC Key Table */ /* Use its own ext address */ updateSeedKeyFromNV(&devInfo,&devKeyInfo); pSeedKeyEnty = getEntryFromSeedKeyTable(devInfo.extAddress,devInfo.shortAddress); /* Do not change the order below to lines */ /* Copy collector ext Address first */ memcpy(commissionDevInfo.extAddress, parentInfo.devInfo.extAddress, sizeof(ApiMac_sAddrExt_t)); addDeviceKey(pSeedKeyEnty,devKeyInfo.deviceKey, true); LCD_WRITE_STRING("KeyInfo recovered", 6); } } #endif Jdllc_rejoin(&devInfo, &parentInfo); rejoining = true; } else { /* Get Start Timestamp */ #ifdef OSAL_PORT2TIRTOS joinTimeTicks = Clock_getTicks(); #else joinTimeTicks = ICall_getTicks(); #endif Jdllc_join(); } /* Clear the event */ Util_clearEvent(&Sensor_events, SENSOR_START_EVT); } /* Is it time to send the next sensor data message? */ if(Sensor_events & SENSOR_READING_TIMEOUT_EVT) { #if !defined(OAD_IMG_A) /* In certification test mode, back to back data shall be sent */ if(!CERTIFICATION_TEST_MODE) { /* Setup for the next message */ Ssf_setReadingClock(configSettings.reportingInterval); } #ifdef FEATURE_SECURE_COMMISSIONING /* if secure Commissioning feature is enabled, read * sensor data and send it only after the secure * commissioning process is done successfully. * else, do not read and send sensor data. */ if(SM_Last_State != SM_CM_InProgress) { #endif //FEATURE_SECURE_COMMISSIONING #if SENSOR_TEST_RAMP_DATA_SIZE processSensorRampMsgEvt(); #else /* Read sensors */ readSensors(); /* Process Sensor Reading Message Event */ processSensorMsgEvt(); #endif //SENSOR_TEST_RAMP_DATA_SIZE #ifdef FEATURE_SECURE_COMMISSIONING } #endif //FEATURE_SECURE_COMMISSIONING #endif //OAD_IMG_A /* Clear the event */ Util_clearEvent(&Sensor_events, SENSOR_READING_TIMEOUT_EVT); } #if defined(OAD_IMG_A) if(Sensor_events & SENSOR_OAD_SEND_RESET_RSP_EVT ) { /* send OAD reset response */ if( false == Oad_hasSentResetRsp) { OADProtocol_Status_t status; status = OADProtocol_sendOadResetRsp(&collectorAddr); if(OADProtocol_Status_Success == status) { //notify to user LCD_WRITE_STRING("Sent Reset Response", 6); Oad_hasSentResetRsp = true; } else { LCD_WRITE_STRING(" Failed to send Reset Response", 6); } } /* Clear the event */ Util_clearEvent(&Sensor_events, SENSOR_OAD_SEND_RESET_RSP_EVT); } #endif //OAD_IMG_A #ifdef DISPLAY_PER_STATS if(Sensor_events & SENSOR_UPDATE_STATS_EVT) { Ssf_displayPerStats(&Sensor_msgStats); /* Clear the event */ Util_clearEvent(&Sensor_events, SENSOR_UPDATE_STATS_EVT); } #endif /* DISPLAY_PER_STATS */ /* Process LLC Events */ Jdllc_process(); /* Allow the Specific functions to process */ Ssf_processEvents(); #ifdef FEATURE_SECURE_COMMISSIONING /* Allow the security manager specific functions to process */ SM_process(); #endif /* FEATURE_SECURE_COMMISSIONING */ /* Don't process ApiMac messages until all of the sensor events are processed. */ #ifdef FEATURE_SECURE_COMMISSIONING /*only if there are no sensor events and security manager events to handle*/ if((Sensor_events == 0) && (SM_events == 0)) #else if(Sensor_events == 0) #endif { /* Wait for response message or events */ ApiMac_processIncoming(); } } /*! * @brief Send MAC data request * * @param type - message type * @param pDstAddr - destination address * @param rxOnIdle - true if not a sleepy device * @param len - length of payload * @param pData - pointer to the buffer * * @return true if sent, false if not */ bool Sensor_sendMsg(Smsgs_cmdIds_t type, ApiMac_sAddr_t *pDstAddr, bool rxOnIdle, uint16_t len, uint8_t *pData) { bool ret = false; ApiMac_mcpsDataReq_t dataReq; /* Timestamp to compute end to end delay */ #ifdef OSAL_PORT2TIRTOS startSensorMsgTimeStamp = Clock_getTicks(); #else startSensorMsgTimeStamp = ICall_getTicks(); #endif /* Fill the data request field */ memset(&dataReq, 0, sizeof(ApiMac_mcpsDataReq_t)); memcpy(&dataReq.dstAddr, pDstAddr, sizeof(ApiMac_sAddr_t)); if(pDstAddr->addrMode == ApiMac_addrType_extended) { dataReq.srcAddrMode = ApiMac_addrType_extended; } else { dataReq.srcAddrMode = ApiMac_addrType_short; } if(rejoining == true) { ApiMac_mlmeGetReqUint16(ApiMac_attribute_panId, &(parentInfo.devInfo.panID)); } dataReq.dstPanId = parentInfo.devInfo.panID; dataReq.msduHandle = getMsduHandle(type); dataReq.txOptions.ack = true; if(CERTIFICATION_TEST_MODE) { dataReq.txOptions.ack = false; } if(rxOnIdle == false) { dataReq.txOptions.indirect = true; } dataReq.msdu.len = len; dataReq.msdu.p = pData; #ifdef FEATURE_MAC_SECURITY #ifdef FEATURE_SECURE_COMMISSIONING { extern ApiMac_sAddrExt_t ApiMac_extAddr; SM_getSrcDeviceSecurityInfo(ApiMac_extAddr, SM_Sensor_SAddress, &dataReq.sec); } #else Jdllc_securityFill(&dataReq.sec); #endif /* FEATURE_SECURE_COMMISSIONING */ #endif /* FEATURE_MAC_SECURITY */ if(type == Smsgs_cmdIds_sensorData || type == Smsgs_cmdIds_rampdata) { Sensor_msgStats.msgsAttempted++; } else if(type == Smsgs_cmdIds_trackingRsp) { Sensor_msgStats.trackingResponseAttempts++; } else if(type == Smsgs_cmdIds_configRsp) { Sensor_msgStats.configResponseAttempts++; } /* Send the message */ if(ApiMac_mcpsDataReq(&dataReq) == ApiMac_status_success) { ret = true; } else { /* handle transaction overflow by retrying */ if(type == Smsgs_cmdIds_sensorData || type == Smsgs_cmdIds_rampdata) { Ssf_setReadingClock(configSettings.reportingInterval); Sensor_msgStats.msgsAttempted++; } } return (ret); } #ifdef IDENTIFY_LED /*! Send LED Identify Request to collector Public function defined in sensor.h */ void Sensor_sendIdentifyLedRequest(void) { uint8_t cmdBytes[SMSGS_INDENTIFY_LED_REQUEST_MSG_LEN]; /* send the response message directly */ cmdBytes[0] = (uint8_t) Smsgs_cmdIds_IdentifyLedReq; cmdBytes[1] = (uint8_t) IDENTIFY_LED_TIME; Sensor_sendMsg(Smsgs_cmdIds_IdentifyLedReq, &collectorAddr, true, SMSGS_INDENTIFY_LED_REQUEST_MSG_LEN, cmdBytes); } #endif /****************************************************************************** Local Functions *****************************************************************************/ /*! * @brief Initialize the clocks. */ static void initializeClocks(void) { /* Initialize the reading clock */ Ssf_initializeReadingClock(); } /*! * @brief MAC Data Confirm callback. * * @param pDataCnf - pointer to the data confirm information */ static void dataCnfCB(ApiMac_mcpsDataCnf_t *pDataCnf) { uint16_t endToEndDelay = 0; /* Record statistics */ if(pDataCnf->status == ApiMac_status_channelAccessFailure) { Sensor_msgStats.channelAccessFailures++; } else if(pDataCnf->status == ApiMac_status_noAck) { Sensor_msgStats.macAckFailures++; #ifdef DISPLAY_PER_STATS Util_setEvent(&Sensor_events, SENSOR_UPDATE_STATS_EVT); #endif } else if(pDataCnf->status != ApiMac_status_success) { Sensor_msgStats.otherDataRequestFailures++; #ifdef DISPLAY_PER_STATS Util_setEvent(&Sensor_events, SENSOR_UPDATE_STATS_EVT); #endif Ssf_displayError("dataCnf: ", pDataCnf->status); } else if(pDataCnf->status == ApiMac_status_success) { Ssf_updateFrameCounter(NULL, pDataCnf->frameCntr); } /* Make sure the message came from the app */ if(pDataCnf->msduHandle & APP_MARKER_MSDU_HANDLE) { /* What message type was the original request? */ if((pDataCnf->msduHandle & APP_MASK_MSDU_HANDLE) == APP_SENSOR_MSDU_HANDLE) { if(pDataCnf->status == ApiMac_status_success) { Sensor_msgStats.msgsSent++; #ifdef DISPLAY_PER_STATS Util_setEvent(&Sensor_events, SENSOR_UPDATE_STATS_EVT); #endif /* Calculate end to end delay */ #ifdef OSAL_PORT2TIRTOS if(Clock_getTicks() < startSensorMsgTimeStamp) { endToEndDelay = Clock_getTicks() + (0xFFFFFFFF-startSensorMsgTimeStamp); } else { endToEndDelay = Clock_getTicks() - startSensorMsgTimeStamp; } #else if(ICall_getTicks() < startSensorMsgTimeStamp) { endToEndDelay = ICall_getTicks() + (0xFFFFFFFF-startSensorMsgTimeStamp); } else { endToEndDelay = ICall_getTicks() - startSensorMsgTimeStamp; } #endif endToEndDelay = endToEndDelay/TICKPERIOD_MS_US; Sensor_msgStats.worstCaseE2EDelay = (Sensor_msgStats.worstCaseE2EDelay > endToEndDelay) ? Sensor_msgStats.worstCaseE2EDelay:endToEndDelay; Sensor_msgStats.avgE2EDelay = (((uint32_t)Sensor_msgStats.avgE2EDelay * (Sensor_msgStats.msgsSent - 1)) + endToEndDelay)/ Sensor_msgStats.msgsSent; } #if CERTIFICATION_TEST_MODE { /* Setup for the next message */ Ssf_setReadingClock(CERT_MODE_INTER_PKT_INTERVAL); } #endif } if((pDataCnf->msduHandle & APP_MASK_MSDU_HANDLE) == APP_TRACKRSP_MSDU_HANDLE) { if(pDataCnf->status == ApiMac_status_success) { Sensor_msgStats.trackingResponseSent++; } } if((pDataCnf->msduHandle & APP_MASK_MSDU_HANDLE) == APP_CONFIGRSP_MSDU_HANDLE) { if(pDataCnf->status == ApiMac_status_success) { Sensor_msgStats.configResponseSent++; } } } } /*! * @brief MAC Data Indication callback. * * @param pDataInd - pointer to the data indication information */ static void dataIndCB(ApiMac_mcpsDataInd_t *pDataInd) { uint8_t cmdBytes[SMSGS_TOGGLE_LED_RESPONSE_MSG_LEN]; if((pDataInd != NULL) && (pDataInd->msdu.p != NULL) && (pDataInd->msdu.len > 0)) { Smsgs_cmdIds_t cmdId = (Smsgs_cmdIds_t)*(pDataInd->msdu.p); #ifdef FEATURE_MAC_SECURITY { if(Jdllc_securityCheck(&(pDataInd->sec)) == false) { /* reject the message */ return; } } #endif /* FEATURE_MAC_SECURITY */ switch(cmdId) { case Smsgs_cmdIds_configReq: processConfigRequest(pDataInd); Sensor_msgStats.configRequests++; break; case Smsgs_cmdIds_trackingReq: /* Make sure the message is the correct size */ if(pDataInd->msdu.len == SMSGS_TRACKING_REQUEST_MSG_LENGTH) { /* Update stats */ Sensor_msgStats.trackingRequests++; /* Indicate tracking message received */ Ssf_trackingUpdate(&pDataInd->srcAddr); /* send the response message directly */ cmdBytes[0] = (uint8_t) Smsgs_cmdIds_trackingRsp; Sensor_sendMsg(Smsgs_cmdIds_trackingRsp, &pDataInd->srcAddr, true, 1, cmdBytes); } break; case Smsgs_cmdIds_toggleLedReq: /* Make sure the message is the correct size */ if(pDataInd->msdu.len == SMSGS_TOGGLE_LED_REQUEST_MSG_LEN) { /* send the response message directly */ cmdBytes[0] = (uint8_t) Smsgs_cmdIds_toggleLedRsp; cmdBytes[1] = Ssf_toggleLED(); Sensor_sendMsg(Smsgs_cmdIds_toggleLedRsp, &pDataInd->srcAddr, true, SMSGS_TOGGLE_LED_RESPONSE_MSG_LEN, cmdBytes); } break; case Smgs_cmdIds_broadcastCtrlMsg: if(parentFound) { /* Node has successfully associated with the network */ processBroadcastCtrlMsg(pDataInd); } break; #ifdef POWER_MEAS case Smsgs_cmdIds_rampdata: Sensor_pwrMeasStats.rampDataRcvd++; break; #endif #ifdef FEATURE_NATIVE_OAD case Smsgs_cmdIds_oad: //Index past the Smsgs_cmdId OADProtocol_ParseIncoming((void*) &(pDataInd->srcAddr), pDataInd->msdu.p + 1); break; #endif //FEATURE_NATIVE_OAD #ifdef FEATURE_SECURE_COMMISSIONING case Smgs_cmdIds_CommissionStart: { ApiMac_sec_t devSec; extern ApiMac_sAddrExt_t ApiMac_extAddr; /* Obtain MAC level security information. Use network key for SM */ Jdllc_securityFill(&devSec); uint8_t *pBuf = pDataInd->msdu.p; pBuf += sizeof(Smsgs_cmdIds_t); SMMsgs_cmdIds_t CMMsgId = (SMMsgs_cmdIds_t)Util_buildUint16(pBuf[0], pBuf[1]); /* read the current value */ ApiMac_mlmeGetReqBool(ApiMac_attribute_autoRequest, &currAutoReq); /* beacon-mode of operation and autoRequest is set to true */ if((CONFIG_BEACON_ORDER != 15) && (currAutoReq == true)) { /* if false enable explicit polling */ ApiMac_mlmeSetReqBool(ApiMac_attribute_autoRequest, false); Util_setEvent(&Jdllc_events, JDLLC_POLL_EVT); } if ((SM_Last_State != SM_CM_InProgress) && (CMMsgId == SMMsgs_cmdIds_KeyRefreshRequest)) { /* Kick off key refreshment process after successful commissioning */ SM_startKeyRefreshProcess(&parentInfo.devInfo, &devSec, parentInfo.fh, true); } else { /* Kick off commissioning process to obtain security information */ SM_startCMProcess(&parentInfo.devInfo, &devSec, parentInfo.fh, true, SM_type_device, SM_SENSOR_AUTH_METHOD); } } break; case Smgs_cmdIds_CommissionMsg: { /* Process Security manager commissioning data */ SM_processCommData(pDataInd); } break; #endif /* FEATURE_SECURE_COMMISSIONING */ default: /* Should not receive other messages */ break; } } } /*! * @brief Get the next MSDU Handle * <BR> * The MSDU handle has 3 parts:<BR> * - The MSBit(7), when set means the the application sent the * message * - Bit 6, when set means that the app message is a config request * - Bits 0-5, used as a message counter that rolls over. * * @param msgType - message command id needed * * @return msdu Handle */ static uint8_t getMsduHandle(Smsgs_cmdIds_t msgType) { uint8_t msduHandle = deviceTxMsduHandle; /* Increment for the next msdu handle, or roll over */ if(deviceTxMsduHandle >= MSDU_HANDLE_MAX) { deviceTxMsduHandle = 0; } else { deviceTxMsduHandle++; } /* Add the App specific bit */ msduHandle |= APP_MARKER_MSDU_HANDLE; /* Add the message type bit */ if(msgType == Smsgs_cmdIds_sensorData || msgType == Smsgs_cmdIds_rampdata) { msduHandle |= APP_SENSOR_MSDU_HANDLE; } else if(msgType == Smsgs_cmdIds_trackingRsp) { msduHandle |= APP_TRACKRSP_MSDU_HANDLE; } else if(msgType == Smsgs_cmdIds_configRsp) { msduHandle |= APP_CONFIGRSP_MSDU_HANDLE; } return (msduHandle); } /*! @brief Build and send fixed size ramp data */ #if SENSOR_TEST_RAMP_DATA_SIZE static void processSensorRampMsgEvt(void) { uint8_t *pMsgBuf; uint16_t index; pMsgBuf = (uint8_t *)Ssf_malloc(SENSOR_TEST_RAMP_DATA_SIZE); if(pMsgBuf) { uint8_t *pBuf = pMsgBuf; *pBuf++ = (uint8_t)Smsgs_cmdIds_rampdata; for(index = 1; index < SENSOR_TEST_RAMP_DATA_SIZE; index++) { *pBuf++ = (uint8_t) (index & 0xFF); } #ifndef POWER_MEAS Board_Led_toggle(board_led_type_LED2); #endif Sensor_sendMsg(Smsgs_cmdIds_rampdata, &collectorAddr, true, SENSOR_TEST_RAMP_DATA_SIZE, pMsgBuf); Ssf_free(pMsgBuf); } } #endif #if !defined(OAD_IMG_A) /*! @brief Build and send sensor data message */ static void processSensorMsgEvt(void) { Smsgs_sensorMsg_t sensor; uint32_t stat; memset(&sensor, 0, sizeof(Smsgs_sensorMsg_t)); ApiMac_mlmeGetReqUint32(ApiMac_attribute_diagRxSecureFail, &stat); Sensor_msgStats.rxDecryptFailures = (uint16_t)stat; ApiMac_mlmeGetReqUint32(ApiMac_attribute_diagTxSecureFail, &stat); Sensor_msgStats.txEncryptFailures = (uint16_t)stat; ApiMac_mlmeGetReqArray(ApiMac_attribute_extendedAddress, sensor.extAddress); /* fill in the message */ sensor.frameControl = configSettings.frameControl; if(sensor.frameControl & Smsgs_dataFields_tempSensor) { memcpy(&sensor.tempSensor, &tempSensor, sizeof(Smsgs_tempSensorField_t)); } if(sensor.frameControl & Smsgs_dataFields_lightSensor) { memcpy(&sensor.lightSensor, &lightSensor, sizeof(Smsgs_lightSensorField_t)); } if(sensor.frameControl & Smsgs_dataFields_humiditySensor) { memcpy(&sensor.humiditySensor, &humiditySensor, sizeof(Smsgs_humiditySensorField_t)); } if(sensor.frameControl & Smsgs_dataFields_msgStats) { memcpy(&sensor.msgStats, &Sensor_msgStats, sizeof(Smsgs_msgStatsField_t)); } if(sensor.frameControl & Smsgs_dataFields_configSettings) { sensor.configSettings.pollingInterval = configSettings.pollingInterval; sensor.configSettings.reportingInterval = configSettings .reportingInterval; } /* inform the user interface */ Ssf_sensorReadingUpdate(&sensor); /* send the data to the collector */ sendSensorMessage(&collectorAddr, &sensor); } /*! * @brief Manually read the sensors */ static void readSensors(void) { #if defined(TEMP_SENSOR) /* Read the temp sensor values */ tempSensor.ambienceTemp = Ssf_readTempSensor(); tempSensor.objectTemp = tempSensor.ambienceTemp; #endif #if defined(HUMIDITY_SENSOR) /* Read the humidity sensor values */ txBuffer[0] = 0xE3; i2cTransaction.slaveAddress = Si7021_ADDR; i2cTransaction.writeBuf = txBuffer; i2cTransaction.writeCount = 1; i2cTransaction.readBuf = rxBuffer; i2cTransaction.readCount = 2; if (I2C_transfer(i2c, &i2cTransaction)) { // char buf[64]; temper = (rxBuffer[0] << 8) | (rxBuffer[1]); temperature = (175.72*temper)/65536; temperature -= 46.85; humiditySensor.temp = temperature; //sprintf(buf,"Buffer:%.2fC\n",temperature); // Display_printf(display, 1, 0, "Temp:%.2fC\n",temperature); LCD_WRITE_STRING_VALUE("Temp:%.2fC\n", temperature, 16, 4); //Display_printf(display, 1, 0, "%s\n",buf); } else { //Display_printf(display, 0, 0, "I2C Bus fault."); LCD_WRITE_STRING("I2C Bus fault\n", 6); } txBuffer[0] = 0xE5; i2cTransaction.slaveAddress = Si7021_ADDR; i2cTransaction.writeBuf = txBuffer; i2cTransaction.writeCount = 1; i2cTransaction.readBuf = rxBuffer; i2cTransaction.readCount = 2; if (I2C_transfer(i2c, &i2cTransaction)) { humi = (rxBuffer[0] << 8) | (rxBuffer[1]); humidity = (125*humi)/65536; humidity -=6; humiditySensor.humidity = humidity; //Display_printf(display, 0, 0, "Humi:%.1f%c",humidity,37); LCD_WRITE_STRING_VALUE("Humi:%.2f", humidity, 16, 4); } else { //Display_printf(display, 0, 0, "I2C Bus fault."); LCD_WRITE_STRING("I2C Bus fault\n", 6); } /* Sleep for 1 second */ // sleep(1); #endif } /*! * @brief Build and send sensor data message * * @param pDstAddr - Where to send the message * @param pMsg - pointer to the sensor data * * @return true if message was sent, false if not */ static bool sendSensorMessage(ApiMac_sAddr_t *pDstAddr, Smsgs_sensorMsg_t *pMsg) { bool ret = false; uint8_t *pMsgBuf; uint16_t len = SMSGS_BASIC_SENSOR_LEN; /* Figure out the length */ if(pMsg->frameControl & Smsgs_dataFields_tempSensor) { len += SMSGS_SENSOR_TEMP_LEN; } if(pMsg->frameControl & Smsgs_dataFields_lightSensor) { len += SMSGS_SENSOR_LIGHT_LEN; } if(pMsg->frameControl & Smsgs_dataFields_humiditySensor) { len += SMSGS_SENSOR_HUMIDITY_LEN; } if(pMsg->frameControl & Smsgs_dataFields_msgStats) { //len += SMSGS_SENSOR_MSG_STATS_LEN; len += sizeof(Smsgs_msgStatsField_t); } if(pMsg->frameControl & Smsgs_dataFields_configSettings) { len += SMSGS_SENSOR_CONFIG_SETTINGS_LEN; } pMsgBuf = (uint8_t *)Ssf_malloc(len); if(pMsgBuf) { uint8_t *pBuf = pMsgBuf; *pBuf++ = (uint8_t)Smsgs_cmdIds_sensorData; memcpy(pBuf, pMsg->extAddress, SMGS_SENSOR_EXTADDR_LEN); pBuf += SMGS_SENSOR_EXTADDR_LEN; pBuf = Util_bufferUint16(pBuf,pMsg->frameControl); /* Buffer data in order of frameControl mask, starting with LSB */ if(pMsg->frameControl & Smsgs_dataFields_tempSensor) { pBuf = Util_bufferUint16(pBuf, pMsg->tempSensor.ambienceTemp); pBuf = Util_bufferUint16(pBuf, pMsg->tempSensor.objectTemp); } if(pMsg->frameControl & Smsgs_dataFields_lightSensor) { pBuf = Util_bufferUint16(pBuf, pMsg->lightSensor.rawData); } if(pMsg->frameControl & Smsgs_dataFields_humiditySensor) { pBuf = Util_bufferUint16(pBuf, pMsg->humiditySensor.temp); pBuf = Util_bufferUint16(pBuf, pMsg->humiditySensor.humidity); } if(pMsg->frameControl & Smsgs_dataFields_msgStats) { pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.joinAttempts); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.joinFails); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.msgsAttempted); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.msgsSent); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.trackingRequests); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.trackingResponseAttempts); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.trackingResponseSent); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.configRequests); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.configResponseAttempts); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.configResponseSent); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.channelAccessFailures); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.macAckFailures); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.otherDataRequestFailures); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.syncLossIndications); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.rxDecryptFailures); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.txEncryptFailures); pBuf = Util_bufferUint16(pBuf, Ssf_resetCount); pBuf = Util_bufferUint16(pBuf, Ssf_resetReseason); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.joinTime); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.interimDelay); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.numBroadcastMsgRcvd); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.numBroadcastMsglost); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.avgE2EDelay); pBuf = Util_bufferUint16(pBuf, pMsg->msgStats.worstCaseE2EDelay); } if(pMsg->frameControl & Smsgs_dataFields_configSettings) { pBuf = Util_bufferUint32(pBuf, pMsg->configSettings.reportingInterval); pBuf = Util_bufferUint32(pBuf, pMsg->configSettings.pollingInterval); } ret = Sensor_sendMsg(Smsgs_cmdIds_sensorData, pDstAddr, true, len, pMsgBuf); Ssf_free(pMsgBuf); } return (ret); } #endif // !defined(OAD_IMG_A) /*! * @brief Process the Config Request message. * * @param pDataInd - pointer to the data indication information */ static void processConfigRequest(ApiMac_mcpsDataInd_t *pDataInd) { Smsgs_statusValues_t stat = Smsgs_statusValues_invalid; Smsgs_configRspMsg_t configRsp; memset(&configRsp, 0, sizeof(Smsgs_configRspMsg_t)); /* Make sure the message is the correct size */ if(pDataInd->msdu.len == SMSGS_CONFIG_REQUEST_MSG_LENGTH) { uint8_t *pBuf = pDataInd->msdu.p; uint16_t frameControl; uint32_t reportingInterval; uint32_t pollingInterval; /* Parse the message */ configSettings.cmdId = (Smsgs_cmdIds_t)*pBuf++; frameControl = Util_parseUint16(pBuf); pBuf += 2; reportingInterval = Util_parseUint32(pBuf); pBuf += 4; pollingInterval = Util_parseUint32(pBuf); stat = Smsgs_statusValues_success; collectorAddr.addrMode = pDataInd->srcAddr.addrMode; if(collectorAddr.addrMode == ApiMac_addrType_short) { collectorAddr.addr.shortAddr = pDataInd->srcAddr.addr.shortAddr; } else { memcpy(collectorAddr.addr.extAddr, pDataInd->srcAddr.addr.extAddr, (APIMAC_SADDR_EXT_LEN)); } configSettings.frameControl = validateFrameControl(frameControl); if(configSettings.frameControl != frameControl) { stat = Smsgs_statusValues_partialSuccess; } configRsp.frameControl = configSettings.frameControl; if((reportingInterval < MIN_REPORTING_INTERVAL) || (reportingInterval > MAX_REPORTING_INTERVAL)) { stat = Smsgs_statusValues_partialSuccess; } else { #ifndef POWER_MEAS configSettings.reportingInterval = reportingInterval; #endif { uint32_t randomNum; randomNum = ((ApiMac_randomByte() << 16) + (ApiMac_randomByte() << 8) + ApiMac_randomByte()); randomNum = (randomNum % reportingInterval) + SENSOR_MIN_POLL_TIME; Ssf_setReadingClock(randomNum); } } configRsp.reportingInterval = configSettings.reportingInterval; if((pollingInterval < MIN_POLLING_INTERVAL) || (pollingInterval > MAX_POLLING_INTERVAL)) { stat = Smsgs_statusValues_partialSuccess; } else { configSettings.pollingInterval = pollingInterval; Jdllc_setPollRate(configSettings.pollingInterval); } configRsp.pollingInterval = configSettings.pollingInterval; } /* Send the response message */ configRsp.cmdId = Smsgs_cmdIds_configRsp; configRsp.status = stat; /* Update the user */ Ssf_configurationUpdate(&configRsp); /* Response the the source device */ sendConfigRsp(&pDataInd->srcAddr, &configRsp); } /*! * @brief Process the Broadcast Control Msg. * * @param pDataInd - pointer to the data indication information */ static void processBroadcastCtrlMsg(ApiMac_mcpsDataInd_t *pDataInd) { Smsgs_broadcastcmdmsg_t broadcastCmd; memset(&broadcastCmd, 0, sizeof(Smsgs_broadcastcmdmsg_t)); /* Make sure the message is the correct size */ if(pDataInd->msdu.len == SMSGS_BROADCAST_CMD_LENGTH) { uint8_t *pBuf = pDataInd->msdu.p; uint16_t broadcastMsgId; /* Parse the message */ uint8_t cmdId = (Smsgs_cmdIds_t)*pBuf++; broadcastMsgId = Util_parseUint16(pBuf); /* Process Broadcast Command Message */ Sensor_msgStats.numBroadcastMsgRcvd++; if(!initBroadcastMsg) { /* Not the first broadcast msg rcvdd after join or a rejoin*/ if((broadcastMsgId - lastRcvdBroadcastMsgId) > 1) { Sensor_msgStats.numBroadcastMsglost += ((broadcastMsgId - lastRcvdBroadcastMsgId) -1); } } lastRcvdBroadcastMsgId = broadcastMsgId; /*To handle the very first broadcast msg rcvdd after join or a rejoin*/ initBroadcastMsg = false; /* Switch On or Off LED based on broadcast Msg Id */ if((broadcastMsgId % 2) == 0) { Ssf_OnLED(); } else { Ssf_OffLED(); } } } /*! * @brief Build and send Config Response message * * @param pDstAddr - Where to send the message * @param pMsg - pointer to the Config Response * * @return true if message was sent, false if not */ static bool sendConfigRsp(ApiMac_sAddr_t *pDstAddr, Smsgs_configRspMsg_t *pMsg) { uint8_t msgBuf[SMSGS_CONFIG_RESPONSE_MSG_LENGTH]; uint8_t *pBuf = msgBuf; *pBuf++ = (uint8_t) Smsgs_cmdIds_configRsp; pBuf = Util_bufferUint16(pBuf, pMsg->status); pBuf = Util_bufferUint16(pBuf, pMsg->frameControl); pBuf = Util_bufferUint32(pBuf, pMsg->reportingInterval); pBuf = Util_bufferUint32(pBuf, pMsg->pollingInterval); return (Sensor_sendMsg(Smsgs_cmdIds_configRsp, pDstAddr, true, SMSGS_CONFIG_RESPONSE_MSG_LENGTH, msgBuf)); } /*! * @brief Filter the frameControl with readings supported by this device. * * @param frameControl - suggested frameControl * * @return new frame control settings supported */ static uint16_t validateFrameControl(uint16_t frameControl) { uint16_t newFrameControl = 0; #if defined(TEMP_SENSOR) if(frameControl & Smsgs_dataFields_tempSensor) { newFrameControl |= Smsgs_dataFields_tempSensor; } #endif #if defined(LIGHT_SENSOR) if(frameControl & Smsgs_dataFields_lightSensor) { newFrameControl |= Smsgs_dataFields_lightSensor; } #endif #if defined(HUMIDITY_SENSOR) if(frameControl & Smsgs_dataFields_humiditySensor) { newFrameControl |= Smsgs_dataFields_humiditySensor; } #endif if(frameControl & Smsgs_dataFields_msgStats) { newFrameControl |= Smsgs_dataFields_msgStats; } if(frameControl & Smsgs_dataFields_configSettings) { newFrameControl |= Smsgs_dataFields_configSettings; } return (newFrameControl); } /*! * @brief The device joined callback. * * @param pDevInfo - This device's information * @param pParentInfo - This is the parent's information */ static void jdllcJoinedCb(ApiMac_deviceDescriptor_t *pDevInfo, Llc_netInfo_t *pParentInfo) { uint32_t randomNum = 0; /* Copy the parent information */ memcpy(&parentInfo, pParentInfo, sizeof(Llc_netInfo_t)); /* Set the collector's address as the parent's address */ if (pParentInfo->fh && CONFIG_RX_ON_IDLE) { collectorAddr.addrMode = ApiMac_addrType_extended; memcpy(collectorAddr.addr.extAddr, pParentInfo->devInfo.extAddress, (APIMAC_SADDR_EXT_LEN)); } else { collectorAddr.addrMode = ApiMac_addrType_short; collectorAddr.addr.shortAddr = pParentInfo->devInfo.shortAddress; } /* Start the reporting timer */ if(CONFIG_FH_ENABLE) { randomNum = ((ApiMac_randomByte() << 16) + (ApiMac_randomByte() << 8) + ApiMac_randomByte()); randomNum = (randomNum % configSettings.reportingInterval) + SENSOR_MIN_POLL_TIME; Ssf_setReadingClock(randomNum); } else { uint32_t randomNum; randomNum = ((ApiMac_randomByte() << 16) + (ApiMac_randomByte() << 8) + ApiMac_randomByte()); randomNum = (randomNum % configSettings.reportingInterval ) + SENSOR_MIN_POLL_TIME; Ssf_setReadingClock(randomNum); } /* Inform the user of the joined information */ Ssf_networkUpdate(rejoining, pDevInfo, pParentInfo); #ifdef FEATURE_SECURE_COMMISSIONING SM_Sensor_SAddress = pDevInfo->shortAddress; #endif if((rejoining == false) && (pParentInfo->fh == false)) { #ifdef FEATURE_MAC_SECURITY ApiMac_status_t stat; /* Add the parent to the security device list */ stat = Jdllc_addSecDevice(pParentInfo->devInfo.panID, pParentInfo->devInfo.shortAddress, &pParentInfo->devInfo.extAddress, 0); if(stat != ApiMac_status_success) { Ssf_displayError("Auth Error: 0x", (uint8_t)stat); } #endif /* FEATURE_MAC_SECURITY */ } #if (CONFIG_SUPERFRAME_ORDER != 15) && defined(MAC_NO_AUTO_REQ) /* * Set MAC Auto Request to false to enable multiple poll requests * per beacon interval */ ApiMac_mlmeSetReqBool(ApiMac_attribute_autoRequest, false); #endif #ifdef OSAL_PORT2TIRTOS /* Calculate Join Time */ if(Clock_getTicks() < joinTimeTicks) { joinTimeTicks = Clock_getTicks() + (0xFFFFFFFF-joinTimeTicks); } else { joinTimeTicks = Clock_getTicks() - joinTimeTicks; } #else /* Calculate Join Time */ if(ICall_getTicks() < joinTimeTicks) { joinTimeTicks = ICall_getTicks() + (0xFFFFFFFF-joinTimeTicks); } else { joinTimeTicks = ICall_getTicks() - joinTimeTicks; } #endif Sensor_msgStats.joinTime = joinTimeTicks / TICKPERIOD_MS_US; #ifdef DISPLAY_PER_STATS /* clear the stats used for PER so that we start out at a * zeroed state */ Sensor_msgStats.macAckFailures = 0; Sensor_msgStats.otherDataRequestFailures = 0; Sensor_msgStats.msgsSent = 0; #endif } /*! * @brief Disassociation indication callback. * * @param pExtAddress - extended address * @param reason - reason for disassociation */ static void jdllcDisassocIndCb(ApiMac_sAddrExt_t *pExtAddress, ApiMac_disassocateReason_t reason) { /* Stop the reporting timer */ Ssf_setReadingClock(0); Ssf_clearNetworkInfo(); #ifdef FEATURE_SECURE_COMMISSIONING SM_removeEntryFromSeedKeyTable(pExtAddress); ApiMac_secDeleteDevice(pExtAddress); Ssf_clearDeviceKeyInfo(); #endif #ifdef FEATURE_NATIVE_OAD /* OAD abort with no auto resume */ OADClient_abort(false); #endif //FEATURE_NATIVE_OAD } /*! * @brief Disassociation confirm callback to an application intiated * disassociation request. * * @param pExtAddress - extended address * @param status - status of disassociation */ static void jdllcDisassocCnfCb(ApiMac_sAddrExt_t *pExtAddress, ApiMac_status_t status) { /* Stop the reporting timer */ Ssf_setReadingClock(0); Ssf_clearNetworkInfo(); #ifdef FEATURE_SECURE_COMMISSIONING SM_removeEntryFromSeedKeyTable(pExtAddress); ApiMac_secDeleteDevice(pExtAddress); Ssf_clearDeviceKeyInfo(); #endif #ifdef FEATURE_NATIVE_OAD /* OAD abort with no auto resume */ OADClient_abort(false); #endif //FEATURE_NATIVE_OAD } /*! * @brief JDLLC state change callback. * * @param state - new state */ static void jdllcStateChangeCb(Jdllc_states_t state) { #ifdef FEATURE_NATIVE_OAD if( (state == Jdllc_states_joined) || (state == Jdllc_states_rejoined)) { #if (CONFIG_SUPERFRAME_ORDER == 15) /* resume an OAD that may have aborted */ OADClient_resume(30000); #else /* resume an OAD that may have aborted */ OADClient_resume(60000); #endif } else if(state == Jdllc_states_orphan) { /* OAD abort with no auto resume */ OADClient_abort(false); } #endif /* FEATURE_NATIVE_OAD */ Ssf_stateChangeUpdate(state); #ifdef OAD_IMG_A if( (state == Jdllc_states_joined) || (state == Jdllc_states_rejoined)) { Util_setEvent(&Sensor_events, SENSOR_OAD_SEND_RESET_RSP_EVT); } #endif } #ifdef FEATURE_SECURE_COMMISSIONING /*! * @brief Security manager failure processing function */ void smFailCMProcessCb(ApiMac_deviceDescriptor_t *devInfo, bool rxOnIdle, bool keyRefreshment) { /* restore, write back current Pib value for auto request attribute */ ApiMac_mlmeSetReqBool(ApiMac_attribute_autoRequest, currAutoReq); if (keyRefreshment == true) { LCD_WRITE_STRING_VALUE("Key Refresh Failed: 0x", SM_Sensor_SAddress, 16, 4); } else { LCD_WRITE_STRING_VALUE("Commissioning Failed: 0x", SM_Sensor_SAddress, 16, 4); } } /*! * @brief Security manager success processing function */ void smSuccessCMProcessCb(ApiMac_deviceDescriptor_t *devInfo, bool keyRefreshment) { /* restore, write back current Pib value for auto request attribute */ ApiMac_mlmeSetReqBool(ApiMac_attribute_autoRequest, currAutoReq); if (keyRefreshment == true) { LCD_WRITE_STRING_VALUE("Key Refreshed: 0x", SM_Sensor_SAddress, 16, 4); } else { LCD_WRITE_STRING_VALUE("Commissioned: 0x", SM_Sensor_SAddress, 16, 4); } } #endif /* FEATURE_SECURE_COMMISSIONING */
/****************************************************************************** @file main.c @brief main entry of the example application Group: WCS LPC Target Device: cc13x0 ****************************************************************************** Copyright (c) 2016-2019, Texas Instruments Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Texas Instruments Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *****************************************************************************/ /****************************************************************************** Includes *****************************************************************************/ #include <xdc/std.h> #include <xdc/runtime/Error.h> #include <xdc/runtime/System.h> #include <ti/sysbios/BIOS.h> #include <ti/sysbios/knl/Task.h> #include <ioc.h> #include "sys_ctrl.h" #include "Board.h" #include "board_led.h" #if defined(DeviceFamily_CC13X0) || defined(DeviceFamily_CC13X2) #include "board_gpio.h" #endif #include <inc/hw_ccfg.h> #include <inc/hw_ccfg_simple_struct.h> /* Header files required for the temporary idle task function */ #include <ti/drivers/Power.h> #include <ti/drivers/power/PowerCC26XX.h> #include <aon_rtc.h> #include <prcm.h> #if defined(FEATURE_BLE_OAD) || defined(FEATURE_NATIVE_OAD) #include <ti/drivers/SPI.h> #endif #ifdef FEATURE_UBLE #include "bleAdv.h" #endif /* FEATURE_UBLE */ #if defined(FEATURE_BLE_OAD) #include "ble_oad/oad_switch.h" #endif /* Header files required to enable instruction fetch cache */ #include <vims.h> #include <hw_memmap.h> #include <ti/sysbios/hal/Hwi.h> #include "cpu.h" #ifdef NV_RESTORE #include "macconfig.h" #ifdef ONE_PAGE_NV #include "nvocop.h" #else #include "nvoctp.h" #endif #endif #include <string.h> #ifdef OSAL_PORT2TIRTOS #include "macTask.h" #include"rom_jt.h" #else #include "api_mac.h" #include "icall.h" #endif #include "ssf.h" #include "uart_printf.h" #include "sensor.h" #if defined(ASSERT_LEDS) #include "board_led.h" #endif #ifndef USE_DEFAULT_USER_CFG #include "mac_user_config.h" /* MAC user defined configuration */ macUserCfg_t macUser0Cfg[] = MAC_USER_CFG; #endif /* USE_DEFAULT_USER_CFG */ #if ((CONFIG_RANGE_EXT_MODE == APIMAC_HIGH_GAIN_MODE) && \ defined(DeviceFamily_CC13X0) && !defined(FREQ_2_4G)) #include "board_palna.h" #endif /****************************************************************************** Constants *****************************************************************************/ /* Assert Reasons */ #define MAIN_ASSERT_ICALL 2 #define MAIN_ASSERT_MAC 3 #define MAIN_ASSERT_HWI_TIRTOS 4 #define MAX_ASSERT_TOGGLE_COUNT 500000 #define RFC_MODE_BLE PRCM_RFCMODESEL_CURR_MODE1 #define RFC_MODE_IEEE PRCM_RFCMODESEL_CURR_MODE2 #define RFC_MODE_ANT PRCM_RFCMODESEL_CURR_MODE4 #define RFC_MODE_EVERYTHING_BUT_ANT PRCM_RFCMODESEL_CURR_MODE5 #define RFC_MODE_EVERYTHING PRCM_RFCMODESEL_CURR_MODE6 /* Extended Address offset in FCFG (LSB..MSB) */ #define EXTADDR_OFFSET 0x2F0 #define APP_TASK_PRIORITY 1 #if defined(DeviceFamily_CC13X2) || (DeviceFamily_CC26X2) #define APP_TASK_STACK_SIZE 1536 #else #define APP_TASK_STACK_SIZE 900 #endif #define SET_RFC_MODE(mode) HWREG( PRCM_BASE + PRCM_O_RFCMODESEL ) = (mode) /****************************************************************************** External Variables *****************************************************************************/ extern ApiMac_sAddrExt_t ApiMac_extAddr; /****************************************************************************** Global Variables *****************************************************************************/ Task_Struct appTask; /* not static so you can see in ROV */ static uint8_t appTaskStack[APP_TASK_STACK_SIZE]; #ifdef OSAL_PORT2TIRTOS static uint8_t _macTaskId; #endif #ifdef NV_RESTORE mac_Config_t Main_user1Cfg = { 0 }; #endif #if defined(BOARD_DISPLAY_USE_UART) UART_Params uartParams; #endif /****************************************************************************** Local Variables *****************************************************************************/ /* Used to check for a valid extended address */ static const uint8_t dummyExtAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; #ifdef NV_RESTORE #ifdef ONE_PAGE_NV /* NVOCOP load API pointers */ static void NVOCOP_loadApiPtrs(NVINTF_nvFuncts_t *pfn) { // Load caller's structure with pointers to the NV API functions pfn->initNV = &NVOCOP_initNV; pfn->compactNV = &NVOCOP_compactNV; pfn->createItem = NULL; pfn->deleteItem = &NVOCOP_deleteItem; pfn->readItem = &NVOCOP_readItem; pfn->writeItem = &NVOCOP_writeItem; pfn->writeItemEx = NULL; pfn->getItemLen = NULL; } #endif #endif /*! * @brief Fill in your own assert function. * * @param assertReason - reason: MAIN_ASSERT_HWI_TIRTOS, * MAIN_ASSERT_ICALL, or * MAIN_ASSERT_MAC */ void Main_assertHandler(uint8_t assertReason) { #if defined(ASSERT_LEDS) int toggleCount = 0; bool toggle = true; Hwi_disable(); while(1) { if(toggleCount == 0) { if(toggle == false) { Board_Led_control(board_led_type_LED1, board_led_state_OFF); Board_Led_control(board_led_type_LED2, board_led_state_OFF); #if !defined(DeviceFamily_CC13X0) && !defined(DeviceFamily_CC26X0) && !defined(DeviceFamily_CC13X2) && !defined(DeviceFamily_CC26X2) Board_Led_control(board_led_type_LED3, board_led_state_OFF); Board_Led_control(board_led_type_LED4, board_led_state_OFF); #endif } else if(toggle == true) { Board_Led_control(board_led_type_LED1, board_led_state_ON); Board_Led_control(board_led_type_LED2, board_led_state_ON); #if !defined(DeviceFamily_CC13X0) && !defined(DeviceFamily_CC26X0) && !defined(DeviceFamily_CC13X2) && !defined(DeviceFamily_CC26X2) Board_Led_control(board_led_type_LED3, board_led_state_ON); Board_Led_control(board_led_type_LED4, board_led_state_ON); #endif } } toggleCount++; if(toggleCount >= MAX_ASSERT_TOGGLE_COUNT) { toggleCount = 0; if(toggle == true) { toggle = false; } else { toggle = true; } } } #else /* ASSERT_LEDS */ Ssf_assertInd(assertReason); /* Pull the plug and start over */ SysCtrlSystemReset(); #endif /* !ASSERT_LEDS */ } /*! * @brief Main task function * * @param a0 - * @param a1 - */ Void appTaskFxn(UArg a0, UArg a1) { #ifdef TIMAC_AGAMA_FPGA /* FPGA build disables POWER constraints */ Power_setConstraint(PowerCC26XX_IDLE_PD_DISALLOW); Power_setConstraint(PowerCC26XX_SB_DISALLOW); IOCPortConfigureSet(IOID_20, IOC_PORT_RFC_GPO0, IOC_STD_OUTPUT); IOCPortConfigureSet(IOID_18, IOC_PORT_RFC_GPI0, IOC_STD_INPUT); // configure RF Core SMI Command Link IOCPortConfigureSet(IOID_22, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_OUT, IOC_STD_OUTPUT); IOCPortConfigureSet(IOID_21, IOC_IOCFG0_PORT_ID_RFC_SMI_CL_IN, IOC_STD_INPUT); #endif #ifndef OSAL_PORT2TIRTOS /* Initialize ICall module */ ICall_init(); #endif /* Copy the extended address from the CCFG area */ memcpy(ApiMac_extAddr, (uint8_t *)&(__ccfg.CCFG_IEEE_MAC_0), (APIMAC_SADDR_EXT_LEN / 2)); memcpy(ApiMac_extAddr + (APIMAC_SADDR_EXT_LEN / 2), (uint8_t *)&(__ccfg.CCFG_IEEE_MAC_1), (APIMAC_SADDR_EXT_LEN / 2)); /* Check to see if the CCFG IEEE is valid */ if(memcmp(ApiMac_extAddr, dummyExtAddr, APIMAC_SADDR_EXT_LEN) == 0) { /* No, it isn't valid. Get the Primary IEEE Address */ memcpy(ApiMac_extAddr, (uint8_t *)(FCFG1_BASE + EXTADDR_OFFSET), (APIMAC_SADDR_EXT_LEN)); } #ifdef NV_RESTORE /* Setup the NV driver */ #ifdef ONE_PAGE_NV NVOCOP_loadApiPtrs(&Main_user1Cfg.nvFps); #else NVOCTP_loadApiPtrs(&Main_user1Cfg.nvFps); #endif if(Main_user1Cfg.nvFps.initNV) { Main_user1Cfg.nvFps.initNV( NULL); } #endif /* Initialize the application */ #ifdef OSAL_PORT2TIRTOS Sensor_init(_macTaskId); #else ICall_createRemoteTasks(); /* Initialize the application */ Sensor_init(); #endif #ifdef FEATURE_BLE_OAD uint8_t blinkCnt = 8; /* blink to let user know sensor is initializing */ while(blinkCnt) { Board_Led_toggle(board_led_type_LED1); Task_sleep(10000); blinkCnt--; } /* reset led back to known state */ Board_Led_control(board_led_type_LED1, board_led_state_OFF); #endif /* FEATURE_BLE_OAD */ /* Kick off application - Forever loop */ while(1) { Sensor_process(); } } /*! * @brief TIRTOS HWI Handler. The name of this function is set to * M3Hwi.excHandlerFunc in app.cfg, you can disable this by * setting it to null. * * @param excStack - TIROS variable * @param lr - TIROS variable */ xdc_Void Main_excHandler(UInt *excStack, UInt lr) { /* User defined function */ Main_assertHandler(MAIN_ASSERT_HWI_TIRTOS); } /*! * @brief HAL assert handler required by OSAL memory module. */ void halAssertHandler(void) { /* User defined function */ Main_assertHandler(MAIN_ASSERT_ICALL); } /*! * @brief MAC HAL assert handler. */ void macHalAssertHandler(void) { /* User defined function */ Main_assertHandler(MAIN_ASSERT_MAC); } /*! * @brief "main()" function - starting point */ int main(void) { Task_Params taskParams; /* float temperature; double temper; float humidity; double humi; uint8_t txBuffer[1]; uint8_t rxBuffer[2]; I2C_Handle i2c; I2C_Params i2cParams; I2C_Transaction i2cTransaction;*/ /* Call driver init functions */ #ifndef USE_DEFAULT_USER_CFG macUser0Cfg[0].pAssertFP = macHalAssertHandler; #endif #if ((CONFIG_RANGE_EXT_MODE == APIMAC_HIGH_GAIN_MODE) && \ defined(DeviceFamily_CC13X0) && !defined(FREQ_2_4G)) macUser0Cfg[0].pSetRE = Board_Palna_initialize; #endif /* Initialization for board related stuff such as LEDs following TI-RTOS convention */ PIN_init(BoardGpioInitTable); #ifdef FEATURE_BLE_OAD /* If FEATURE_BLE_OAD is enabled, look for a left button * press on reset. This indicates to revert to some * factory image */ if(!PIN_getInputValue(Board_PIN_BUTTON0)) { OAD_markSwitch(); } #endif /* FEATURE_BLE_OAD */ #if defined(POWER_MEAS) /* Disable external flash for power measurements */ Board_shutDownExtFlash(); #endif #if defined(FEATURE_BLE_OAD) || defined(FEATURE_NATIVE_OAD) SPI_init(); #endif #ifndef POWER_MEAS #if defined(BOARD_DISPLAY_USE_UART) /* Enable System_printf(..) UART output */ UART_init(); UART_Params_init(&uartParams); #ifndef TIMAC_AGAMA_FPGA uartParams.baudRate = 115200; #else uartParams.baudRate = 460800; #endif UartPrintf_init(UART_open(Board_UART0, &uartParams)); #endif /* BOARD_DISPLAY_USE_UART */ #endif #ifdef OSAL_PORT2TIRTOS _macTaskId = macTaskInit(macUser0Cfg); #endif /* Configure task. */ Task_Params_init(&taskParams); taskParams.stack = appTaskStack; taskParams.stackSize = APP_TASK_STACK_SIZE; taskParams.priority = APP_TASK_PRIORITY; Task_construct(&appTask, appTaskFxn, &taskParams, NULL); #ifdef DEBUG_SW_TRACE IOCPortConfigureSet(IOID_8, IOC_PORT_RFC_TRC, IOC_STD_OUTPUT | IOC_CURRENT_4MA | IOC_SLEW_ENABLE); #endif /* DEBUG_SW_TRACE */ /* I2C_Params_init(&i2cParams); i2cParams.bitRate = I2C_400kHz; i2c = I2C_open(Board_I2C_TMP, &i2cParams); if (i2c == NULL) { LCD_WRITE_STRING("Error Initializing I2C\n", 6); while (1); } else { LCD_WRITE_STRING("I2C Initialized!\n", 6); }*/ BIOS_start(); /* enable interrupts and start SYS/BIOS */ return (0); }