/************************************************************************************************** Filename: znp_app.c Revised: $Date: 2011-06-01 14:52:32 -0700 (Wed, 01 Jun 2011) $ Revision: $Revision: 26173 $ Description: This file is the Application implementation for the ZNP. Copyright 2009-2011 Texas Instruments Incorporated. All rights reserved. IMPORTANT: Your use of this Software is limited to those specific rights granted under the terms of a software license agreement between the user who downloaded the software, his/her employer (which must be your employer) and Texas Instruments Incorporated (the "License"). You may not use this Software unless you agree to abide by the terms of the License. The License limits your use, and you acknowledge, that the Software may not be modified, copied or distributed unless embedded on a Texas Instruments microcontroller or used solely and exclusively in conjunction with a Texas Instruments radio frequency transceiver, which is integrated into your product. Other than for the foregoing purpose, you may not use, reproduce, copy, prepare derivative works of, modify, distribute, perform, display or sell this Software and/or its documentation for any purpose. YOU FURTHER ACKNOWLEDGE AND AGREE THAT THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL TEXAS INSTRUMENTS OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. Should you have any questions regarding your right to use this Software, contact Texas Instruments Incorporated at www.TI.com. **************************************************************************************************/ /* ------------------------------------------------------------------------------------------------ * Includes * ------------------------------------------------------------------------------------------------ */ #include "hal_board_cfg.h" #include "mac_radio_defs.h" #include "MT.h" #include "MT_AF.h" #include "MT_SYS.h" #include "MT_ZDO.h" #include "MT_UART.h" #include "MT_UTIL.h" #include "OSAL.h" #include "OSAL_Nv.h" #if defined POWER_SAVING || defined CC2531ZNP #include "OSAL_PwrMgr.h" #endif #include "ZComDef.h" #include "ZMAC.h" #include "znp_app.h" #include "znp_spi.h" /* ------------------------------------------------------------------------------------------------ * Local Functions * ------------------------------------------------------------------------------------------------ */ static void npInit(void); static void npInitNV(void); static void npUartCback(uint8 port, uint8 event); static void npUartTxReady(void); static uint8* npMtUartAlloc(uint8 cmd0, uint8 len); static void npMtUartSend(uint8 *pBuf); #if !defined CC2531ZNP static uint8* npMtSpiAlloc(uint8 cmd0, uint8 len); static void npMtSpiSend(uint8 *pBuf); uint8* npSpiPollCallback(void); bool npSpiReadyCallback(void); #endif /* ------------------------------------------------------------------------------------------------ * Local Variables * ------------------------------------------------------------------------------------------------ */ static osal_msg_q_t npTxQueue; /* ------------------------------------------------------------------------------------------------ * Global Variables * ------------------------------------------------------------------------------------------------ */ uint8 znpCfg1; uint8 znpCfg0; #if defined TC_LINKKEY_JOIN extern uint8 zcl_TaskID; extern void zclProcessMessageMSG(afIncomingMSGPacket_t *pkt); #endif /************************************************************************************************** * @fn znpInit * * @brief This function is the OSAL task initialization callback. * * input parameters * * @param taskId - The task ID assigned to this task by the OSAL. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void znpInit(uint8 taskId) { znpTaskId = taskId; osal_set_event(taskId, ZNP_SECONDARY_INIT_EVENT); } /************************************************************************************************** * @fn znpEventLoop * * @brief This function processes the OSAL events and messages for the application. * * input parameters * * @param taskId - The task ID assigned to this application by OSAL at system initialization. * @param events - A bit mask of the pending event(s). * * output parameters * * None. * * @return The events bit map received via parameter with the bits cleared which correspond to * the event(s) that were processed on this invocation. ************************************************************************************************** */ uint16 znpEventLoop(uint8 taskId, uint16 events) { osal_event_hdr_t *pMsg; #if !defined CC2531ZNP uint8 *pBuf; #endif if (events & SYS_EVENT_MSG) { if ((pMsg = (osal_event_hdr_t *) osal_msg_receive(znpTaskId)) != NULL) { switch (pMsg->event) { /* incoming message from UART transport */ case CMD_SERIAL_MSG: MT_ProcessIncoming(((mtOSALSerialData_t *)pMsg)->msg); break; #if defined TC_LINKKEY_JOIN #if defined (MT_UTIL_FUNC) case ZCL_KEY_ESTABLISH_IND: MT_UtilKeyEstablishInd((keyEstablishmentInd_t *)pMsg); break; #endif #endif case AF_INCOMING_MSG_CMD: #if defined TC_LINKKEY_JOIN if (ZCL_KEY_ESTABLISHMENT_ENDPOINT == (((afIncomingMSGPacket_t *)pMsg)->endPoint)) { zclProcessMessageMSG((afIncomingMSGPacket_t *)pMsg); } else #endif { MT_AfIncomingMsg((afIncomingMSGPacket_t *)pMsg); } break; #ifdef MT_ZDO_FUNC case ZDO_STATE_CHANGE: MT_ZdoStateChangeCB(pMsg); break; case ZDO_CB_MSG: MT_ZdoSendMsgCB((zdoIncomingMsg_t *)pMsg); break; #endif case AF_DATA_CONFIRM_CMD: MT_AfDataConfirm((afDataConfirm_t *)pMsg); break; default: break; } osal_msg_deallocate((byte *)pMsg); } events ^= SYS_EVENT_MSG; } #if !defined CC2531ZNP else if (events & ZNP_SPI_RX_AREQ_EVENT) { if ((pBuf = npSpiGetReqBuf()) != NULL ) { MT_ProcessIncoming(pBuf); npSpiAReqComplete(); } events ^= ZNP_SPI_RX_AREQ_EVENT; } else if (events & ZNP_SPI_RX_SREQ_EVENT) { if ((pBuf = npSpiGetReqBuf()) != NULL) { MT_ProcessIncoming(pBuf); } events ^= ZNP_SPI_RX_SREQ_EVENT; } #endif else if (events & ZNP_UART_TX_READY_EVENT) { npUartTxReady(); events ^= ZNP_UART_TX_READY_EVENT; } #if defined MT_SYS_FUNC else if (events & MT_SYS_OSAL_EVENT_0) { MT_SysOsalTimerExpired(0x00); events ^= MT_SYS_OSAL_EVENT_0; } else if (events & MT_SYS_OSAL_EVENT_1) { MT_SysOsalTimerExpired(0x01); events ^= MT_SYS_OSAL_EVENT_1; } else if (events & MT_SYS_OSAL_EVENT_2) { MT_SysOsalTimerExpired(0x02); events ^= MT_SYS_OSAL_EVENT_2; } else if (events & MT_SYS_OSAL_EVENT_3) { MT_SysOsalTimerExpired(0x03); events ^= MT_SYS_OSAL_EVENT_3; } #endif #if defined POWER_SAVING else if (events & ZNP_PWRMGR_CONSERVE_EVENT) { (void)osal_pwrmgr_task_state(znpTaskId, PWRMGR_CONSERVE); events ^= ZNP_PWRMGR_CONSERVE_EVENT; } #endif else if (events & ZNP_SECONDARY_INIT_EVENT) { npInit(); events ^= ZNP_SECONDARY_INIT_EVENT; } else if (events & MT_AF_EXEC_EVT) { MT_AfExec(); events ^= MT_AF_EXEC_EVT; } else { events = 0; /* Discard unknown events. */ } return ( events ); } /************************************************************************************************** * @fn MT_TransportAlloc * * @brief This function is the definition of the physical transport API for allocation a msg. * * input parameters * * @param cmd0 - The RPC command byte 0. * @param len - The RPC data length. * * output parameters * * @param uint8 * - Pointer to the buffer to use build and send the RPC message. * * @return None. ************************************************************************************************** */ uint8 *MT_TransportAlloc(uint8 cmd0, uint8 len) { #if !defined CC2531ZNP if (ZNP_CFG1_UART == znpCfg1) #endif { return npMtUartAlloc(cmd0, len); } #if !defined CC2531ZNP else { return npMtSpiAlloc(cmd0, len); } #endif } /************************************************************************************************** * @fn MT_TransportSend * * @brief This function is the definition of the physical transport API for sending a message. * * input parameters * * @param pBuf - Pointer to the buffer created with MT_TransportAlloc. * * output parameters * * None. * * @return None. ************************************************************************************************** */ void MT_TransportSend(uint8 *pBuf) { #if !defined CC2531ZNP if (ZNP_CFG1_UART == znpCfg1) #endif { npMtUartSend(pBuf); } #if !defined CC2531ZNP else { npMtSpiSend(pBuf); } #endif } /************************************************************************************************** * @fn npInit * * @brief This function is the secondary initialization that resolves conflicts during * osalInitTasks(). For example, since ZNP is the highest priority task, and * specifically because the ZNP task is initialized before the ZDApp task, if znpInit() * registers anything with ZDO_RegisterForZdoCB(), it is wiped out when ZDApp task * initialization invokes ZDApp_InitZdoCBFunc(). * There may be other existing or future such races, so try to do all possible * NP initialization here vice in znpInit(). * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void npInit(void) { if (ZNP_CFG1_UART == znpCfg1) { halUARTCfg_t uartConfig; uartConfig.configured = TRUE; uartConfig.baudRate = ZNP_UART_BAUD; uartConfig.flowControl = TRUE; uartConfig.flowControlThreshold = HAL_UART_FLOW_THRESHOLD; uartConfig.rx.maxBufSize = HAL_UART_RX_BUF_SIZE; uartConfig.tx.maxBufSize = HAL_UART_TX_BUF_SIZE; uartConfig.idleTimeout = HAL_UART_IDLE_TIMEOUT; uartConfig.intEnable = TRUE; uartConfig.callBackFunc = npUartCback; HalUARTOpen(HAL_UART_PORT, &uartConfig); MT_UartRegisterTaskID(znpTaskId); } else { //npSpiInit() is called by hal_spi.c: HalSpiInit(). } npInitNV(); MT_Init(); #if defined TC_LINKKEY_JOIN zcl_TaskID = znpTaskId; #endif #if LQI_ADJUST ZMacLqiAdjustMode(LQI_ADJ_MODE1); #endif #if defined CC2531ZNP (void)osal_pwrmgr_task_state(znpTaskId, PWRMGR_HOLD); #endif } /************************************************************************************************** * @fn npInitNV * * @brief * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void npInitNV(void) { /* 4 x 2 bytes ZNP_NV_APP_ITEM_X */ osal_nv_item_init(ZNP_NV_APP_ITEM_1, 2, NULL); osal_nv_item_init(ZNP_NV_APP_ITEM_2, 2, NULL); osal_nv_item_init(ZNP_NV_APP_ITEM_3, 2, NULL); osal_nv_item_init(ZNP_NV_APP_ITEM_4, 2, NULL); /* 2 x 16 bytes ZNP_NV_APP_ITEM_X */ osal_nv_item_init(ZNP_NV_APP_ITEM_5, 16, NULL); osal_nv_item_init(ZNP_NV_APP_ITEM_6, 16, NULL); } /************************************************************************************************** * @fn npUartCback * * @brief This function is the UART callback processor. * * input parameters * * @param port - The port being used for UART. * @param event - The reason for the callback. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void npUartCback(uint8 port, uint8 event) { switch (event) { case HAL_UART_RX_FULL: case HAL_UART_RX_ABOUT_FULL: case HAL_UART_RX_TIMEOUT: MT_UartProcessZToolData(port, znpTaskId); break; case HAL_UART_TX_EMPTY: osal_set_event(znpTaskId, ZNP_UART_TX_READY_EVENT); break; default: break; } } /************************************************************************************************** * @fn npUartTxReady * * @brief This function gets and writes the next chunk of data to the UART. * * input parameters * * None. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void npUartTxReady(void) { static uint16 npUartTxCnt = 0; static uint8 *npUartTxMsg = NULL; static uint8 *pMsg = NULL; if (!npUartTxMsg) { if ((pMsg = npUartTxMsg = osal_msg_dequeue(&npTxQueue))) { /* | SOP | Data Length | CMD | DATA | FSC | * | 1 | 1 | 2 | as dLen | 1 | */ npUartTxCnt = pMsg[1] + MT_UART_FRAME_OVHD + MT_RPC_FRAME_HDR_SZ; } } if (npUartTxMsg) { uint16 len = HalUARTWrite(HAL_UART_PORT, pMsg, npUartTxCnt); npUartTxCnt -= len; if (npUartTxCnt == 0) { osal_msg_deallocate(npUartTxMsg); npUartTxMsg = NULL; } else { pMsg += len; } } } /************************************************************************************************** * @fn npMtUartAlloc * * @brief This function allocates a buffer for Txing on UART. * * input parameters * * @param cmd0 - The first byte of the MT command id containing the command type and subsystem. * @param len - Data length required. * * output parameters * * None. * * @return Pointer to the buffer obtained; possibly NULL if an allocation failed. ************************************************************************************************** */ static uint8* npMtUartAlloc(uint8 cmd0, uint8 len) { uint8 *p; if ((p = osal_msg_allocate(len + MT_RPC_FRAME_HDR_SZ + MT_UART_FRAME_OVHD)) != NULL) { return p + 1; } return NULL; } /************************************************************************************************** * @fn npMtUartSend * * @brief This function transmits or enqueues the buffer for transmitting on UART. * * input parameters * * @param pBuf - Pointer to the buffer to transmit on the UART. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void npMtUartSend(uint8 *pBuf) { uint8 len = pBuf[0] + MT_RPC_FRAME_HDR_SZ; pBuf[len] = MT_UartCalcFCS(pBuf, len); pBuf--; pBuf[0] = MT_UART_SOF; osal_msg_enqueue(&npTxQueue, pBuf); osal_set_event(znpTaskId, ZNP_UART_TX_READY_EVENT); } #if !defined CC2531ZNP /************************************************************************************************** * @fn npMtSpiAlloc * * @brief This function gets or allocates a buffer for Txing on SPI. * * input parameters * * @param cmd0 - The first byte of the MT command id containing the command type and subsystem. * @param len - Data length required. * * output parameters * * None. * * @return Pointer to the buffer obtained; possibly NULL if an allocation failed. ************************************************************************************************** */ static uint8* npMtSpiAlloc(uint8 cmd0, uint8 len) { if ((cmd0 & MT_RPC_CMD_TYPE_MASK) == MT_RPC_CMD_SRSP) { return npSpiSRspAlloc(len); } else { return npSpiAReqAlloc(len); } } /************************************************************************************************** * @fn npMtSpiSend * * @brief This function transmits or enqueues the buffer for transmitting on SPI. * * input parameters * * @param pBuf - Pointer to the buffer to transmit on the SPI. * * output parameters * * None. * * @return None. ************************************************************************************************** */ static void npMtSpiSend(uint8 *pBuf) { if ((pBuf[1] & MT_RPC_CMD_TYPE_MASK) == MT_RPC_CMD_SRSP) { npSpiSRspReady(pBuf); } else { osal_msg_enqueue(&npTxQueue, pBuf); npSpiAReqReady(); } } /************************************************************************************************** * @fn npSpiPollCallback * * @brief This function is called by the SPI driver when a POLL frame is received. * * input parameters * * None. * * output parameters * * None. * * @return A pointer to an OSAL message buffer containing the next AREQ frame to transmit, * if any; NULL otherwise. ************************************************************************************************** */ uint8* npSpiPollCallback(void) { return osal_msg_dequeue(&npTxQueue); } /************************************************************************************************** * @fn npSpiReadyCallback * * @brief This function is called by the SPI driver to check if any data is ready to send. * * input parameters * * None. * * output parameters * * None. * * @return TRUE if data is ready to send; FALSE otherwise. ************************************************************************************************** */ bool npSpiReadyCallback(void) { return !OSAL_MSG_Q_EMPTY(&npTxQueue); } #endif /************************************************************************************************** */