/******************************************************************************* File Name: m2m_hif.c Summary: This module contains M2M host interface API implementations. Description: This module contains M2M host interface API implementations. *******************************************************************************/ //DOM-IGNORE-BEGIN /******************************************************************************* * Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries. * * Subject to your compliance with these terms, you may use Microchip software * and any derivatives exclusively with Microchip products. It is your * responsibility to comply with third party license terms applicable to your * use of third party software (including open source software) that may * accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A * PARTICULAR PURPOSE. * * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN * ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. *******************************************************************************/ #include "nm_common.h" #include "nmbus.h" #include "nmdrv.h" #include "nm_bsp.h" #include "m2m_hif.h" #include "m2m_types.h" #include "nmasic.h" #include "m2m_periph.h" //#include "wdrv_winc_common.h" //#include "osal/osal.h" #define NMI_AHB_DATA_MEM_BASE 0x30000 #define NMI_AHB_SHARE_MEM_BASE 0xd0000 #define WIFI_HOST_RCV_CTRL_0 (0x1070) #define WIFI_HOST_RCV_CTRL_1 (0x1084) #define WIFI_HOST_RCV_CTRL_2 (0x1078) #define WIFI_HOST_RCV_CTRL_3 (0x106c) #define WIFI_HOST_RCV_CTRL_4 (0x150400) #define INTERRUPT_CORTUS_0_3000D0 (0x10a8) #define INTERRUPT_CORTUS_1_3000D0 (0x10ac) #define INTERRUPT_CORTUS_2_3000D0 (0x10b0) #define INTERRUPT_CORTUS_3_3000D0 (0x10b4) //static OSAL_SEM_HANDLE_TYPE hifSemaphore; typedef struct { uint8_t u8ChipMode; uint8_t u8ChipSleep; uint8_t u8HifRXDone; uint8_t u8Interrupt; uint32_t u32RxAddr; uint32_t u32RxSize; tpfHifCallBack pfWifiCb; tpfHifCallBack pfIpCb; tpfHifCallBack pfOtaCb; tpfHifCallBack pfSigmaCb; tpfHifCallBack pfHifCb; //tpfHifCallBack pfCryptoCb; tpfHifCallBack pfSslCb; } tstrHifContext; volatile tstrHifContext gstrHifCxt; /* Special codes for managing HIF restriction to OTA rollback/switch only */ #define HIF_OTA_RB_ONLY 0xFFFF #define HIFCODE_OTA_RB ((M2M_REQ_GROUP_OTA << 8) | M2M_OTA_REQ_ROLLBACK) #define HIFCODE_OTA_SW ((M2M_REQ_GROUP_OTA << 8) | M2M_OTA_REQ_SWITCH_FIRMWARE) /* Codes for new HIF messages (since last HIF major increase). Only need ones which are host->winc. Each entry is formed of ((GroupId << 8) | OpCode) */ #define HIFCODE_SSL_WRITECERT ((M2M_REQ_GROUP_SSL << 8) | M2M_SSL_REQ_WRITE_OWN_CERTS) #define HIFCODE_WIFI_PASSIVESCAN ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_PASSIVE_SCAN) #define HIFCODE_WIFI_CONN ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_CONN) #define HIFCODE_WIFI_CONN_PARAM ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_IND_CONN_PARAM) #define HIFCODE_WIFI_DELETE_CRED ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQRSP_DELETE_APID) #define HIFCODE_WIFI_START_PROV_MODE ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_START_PROVISION_MODE) #define HIFCODE_WIFI_ENABLE_AP ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_ENABLE_AP) #define HIFCODE_IP_RAW_SOCK_OPT ((M2M_REQ_GROUP_IP << 8) | SOCKET_CMD_RAW_SET_SOCK_OPT) #define HIFCODE_WIFI_ROAMING ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_ROAMING) #define HIFCODE_IP_SECURE ((M2M_REQ_GROUP_IP << 8) | SOCKET_CMD_SECURE) #define HIFCODE_WIFI_SCAN_SSID_LIST ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_SCAN_SSID_LIST) #define HIFCODE_WIFI_SET_STOP_SCAN_OPTION ((M2M_REQ_GROUP_WIFI << 8) | M2M_WIFI_REQ_SET_STOP_SCAN_OPTION) /* List of new HIF messages (since last HIF major increase). Only need to list ones which are host->winc. Additionally, entry 0 used to indicate OTA RB/SW only. */ #define NEW_HIF_LIST \ HIF_OTA_RB_ONLY, \ HIFCODE_SSL_WRITECERT, \ HIFCODE_WIFI_PASSIVESCAN, \ HIFCODE_WIFI_CONN, \ HIFCODE_WIFI_CONN_PARAM, \ HIFCODE_WIFI_DELETE_CRED, \ HIFCODE_WIFI_START_PROV_MODE, \ HIFCODE_WIFI_ENABLE_AP, \ HIFCODE_IP_RAW_SOCK_OPT, \ HIFCODE_WIFI_ROAMING, \ HIFCODE_IP_SECURE, \ HIFCODE_WIFI_SCAN_SSID_LIST, \ HIFCODE_WIFI_SET_STOP_SCAN_OPTION /* Array of HIF messages which are not supported by Firmware. During hif_init() this array is rebased using an offset determined by Firmware HIF level. */ static uint16_t gau16HifBlacklist[] = {NEW_HIF_LIST}; #define HIF_BLACKLIST_SZ (sizeof(gau16HifBlacklist)/sizeof(gau16HifBlacklist[0])) static uint8_t gu8HifBlOffset = 0; static int8_t hif_set_rx_done(void) { uint32_t reg; int8_t ret = M2M_SUCCESS; gstrHifCxt.u8HifRXDone = 0; if (ISNMC3400(nmi_get_chipid())) { ret = nm_write_reg(INTERRUPT_CORTUS_0_3000D0, 1); if(ret != M2M_SUCCESS)goto ERR1; } else { ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, ®); if(ret != M2M_SUCCESS)goto ERR1; /* Set RX Done */ reg |= NBIT1; ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0, reg); if(ret != M2M_SUCCESS)goto ERR1; } ERR1: return ret; } /** * @fn static void m2m_hif_cb(uint8_t u8OpCode, uint16_t u16DataSize, uint32_t u32Addr) * @brief WiFi call back function * @param[in] u8OpCode * HIF Opcode type. * @param[in] u16DataSize * HIF data length. * @param[in] u32Addr * HIF address. */ static void m2m_hif_cb(uint8_t u8OpCode, uint16_t u16DataSize, uint32_t u32Addr) { } /** * @fn int8_t hif_chip_wake(void); * @brief To Wakeup the chip. * @return The function shall return ZERO for successful operation and a negative value otherwise. */ int8_t hif_chip_wake(void) { int8_t ret = M2M_SUCCESS; if(gstrHifCxt.u8HifRXDone) { /* chip already wake for the rx not done no need to send wake request */ return ret; } if(gstrHifCxt.u8ChipSleep == 0) { if(gstrHifCxt.u8ChipMode != M2M_NO_PS) { ret = chip_wake(); if(ret != M2M_SUCCESS)goto ERR1; } } gstrHifCxt.u8ChipSleep++; ERR1: return ret; } /*! @fn \ void hif_set_sleep_mode(uint8_t u8Pstype); @brief Set the sleep mode of the HIF layer. @param [in] u8Pstype Sleep mode. @return The function SHALL return 0 for success and a negative value otherwise. */ void hif_set_sleep_mode(uint8_t u8Pstype) { gstrHifCxt.u8ChipMode = u8Pstype; } /*! @fn \ uint8_t hif_get_sleep_mode(void); @brief Get the sleep mode of the HIF layer. @return The function SHALL return the sleep mode of the HIF layer. */ uint8_t hif_get_sleep_mode(void) { return gstrHifCxt.u8ChipMode; } /** * @fn int8_t hif_chip_sleep_sc(void); * @brief To clear the chip sleep but keep the chip sleep * @return The function shall return ZERO for successful operation and a negative value otherwise. */ static int8_t hif_chip_sleep_sc(void) { if(gstrHifCxt.u8ChipSleep >= 1) { gstrHifCxt.u8ChipSleep--; } return M2M_SUCCESS; } /** * @fn int8_t hif_chip_sleep(void); * @brief To make the chip sleep. * @return The function shall return ZERO for successful operation and a negative value otherwise. */ int8_t hif_chip_sleep(void) { int8_t ret = M2M_SUCCESS; if(gstrHifCxt.u8ChipSleep >= 1) { gstrHifCxt.u8ChipSleep--; } if(gstrHifCxt.u8ChipSleep == 0) { if(gstrHifCxt.u8ChipMode != M2M_NO_PS) ret = chip_sleep(); } return ret; } /** * @fn int8_t hif_init(void * arg); * @brief To initialize HIF layer. * @param[in] arg * Pointer to the arguments. * @return The function shall return ZERO for successful operation and a negative value otherwise. */ int8_t hif_init(void *arg) { memset((uint8_t*)&gstrHifCxt, 0, sizeof(tstrHifContext)); // if (OSAL_RESULT_TRUE != OSAL_SEM_Create(&hifSemaphore, OSAL_SEM_TYPE_BINARY, 1, 1)) // return M2M_ERR_INIT; hif_register_cb(M2M_REQ_GROUP_HIF, m2m_hif_cb); return hif_chip_sleep(); } /** * @fn int8_t hif_deinit(void * arg); * @brief To Deinitialize HIF layer. * @param[in] arg * Pointer to the arguments. * @return The function shall return ZERO for successful operation and a negative value otherwise. */ int8_t hif_deinit(void *arg) { int8_t ret = M2M_SUCCESS; ret = hif_chip_wake(); memset((uint8_t*)&gstrHifCxt, 0, sizeof(tstrHifContext)); return ret; } /** * @fn int8_t hif_check_compatibility(uint16_t u16HifInfo); * @brief * To check the compatibility of an image with the current driver. * @param [in] u16HifInfo * HIF info of image to be checked. * @return The function shall return ZERO for compatible image and a negative value otherwise. */ int8_t hif_check_compatibility(uint16_t u16HifInfo) { int8_t ret = M2M_ERR_FW_VER_MISMATCH; if((M2M_GET_HIF_BLOCK(u16HifInfo) == M2M_HIF_BLOCK_VALUE) && (M2M_GET_HIF_MAJOR(u16HifInfo) == M2M_HIF_MAJOR_VALUE)) { ret = M2M_SUCCESS; } return ret; } /** * @fn int8_t hif_enable_access(void); * @brief * To enable access to HIF layer, based on HIF level of Firmware. * This function reads HIF level directly from a register written by Firmware. * @return The function shall return ZERO for full match operation and a negative value if operation is restricted. */ int8_t hif_enable_access(void) { int8_t ret = M2M_SUCCESS; uint16_t fw_hif_info = 0; ret = nm_get_hif_info(&fw_hif_info, NULL); if(ret == M2M_SUCCESS) { ret = hif_check_compatibility(fw_hif_info); if(ret == M2M_SUCCESS) { switch(M2M_GET_HIF_MINOR(fw_hif_info)) { case 0: gu8HifBlOffset = 1; break; case 1: gu8HifBlOffset = 2; break; case 2: gu8HifBlOffset = 2; break; case 3: gu8HifBlOffset = 3; break; case 4: gu8HifBlOffset = 10; break; case 5: gu8HifBlOffset = 13; break; // Additional case to be added each time hif minor increments. // All additional cases to be removed in the event of a hif major increment. // Default catches all cases in which hif minor is greater in Firmware than in Driver. default: gu8HifBlOffset = HIF_BLACKLIST_SZ; break; } } else { gu8HifBlOffset = 0; M2M_ERR("HIF access limited to OTA Switch/Rollback only\r\n"); } } return ret; } /** * @fn int8_t hif_check_code(uint8_t u8Gid, uint8_t u8OpCode); * @brief * To check that a particular hif message is supported with the current driver/firmware pair. * @param[in] u8Gid * Group ID. * @param[in] u8Opcode * Operation ID. * @return The function shall return @ref M2M_SUCCESS for success and a negative value otherwise. */ int8_t hif_check_code(uint8_t u8Gid, uint8_t u8OpCode) { uint8_t u8BlId; uint16_t u16HifCode = ((uint16_t)u8Gid<<8) | u8OpCode; if((u16HifCode == HIFCODE_OTA_RB) || (u16HifCode == HIFCODE_OTA_SW)) { return M2M_SUCCESS; } if(gu8HifBlOffset == 0) { M2M_ERR("HIF OTA rb/sw only\r\n"); return M2M_ERR_SEND; } for(u8BlId = gu8HifBlOffset; u8BlId < HIF_BLACKLIST_SZ; u8BlId++) { if(u16HifCode == gau16HifBlacklist[u8BlId]) { M2M_ERR("HIF message unsupported\r\n"); return M2M_ERR_SEND; } } return M2M_SUCCESS; } /** * @fn int8_t hif_send(uint8_t u8Gid,uint8_t u8Opcode,uint8_t *pu8CtrlBuf,uint16_t u16CtrlBufSize, * uint8_t *pu8DataBuf,uint16_t u16DataSize, uint16_t u16DataOffset) * @brief Send packet using host interface. * * @param[in] u8Gid * Group ID. * @param[in] u8Opcode * Operation ID. * @param[in] pu8CtrlBuf * Pointer to the Control buffer. * @param[in] u16CtrlBufSize * Control buffer size. * @param[in] u16DataOffset * Packet Data offset. * @param[in] pu8DataBuf * Packet buffer Allocated by the caller. * @param[in] u16DataSize * Packet buffer size (including the HIF header). * @return The function shall return @ref M2M_SUCCESS for successful operation and a negative value otherwise. */ int8_t hif_send(uint8_t u8Gid, uint8_t u8Opcode, uint8_t *pu8CtrlBuf, uint16_t u16CtrlBufSize, uint8_t *pu8DataBuf, uint16_t u16DataSize, uint16_t u16DataOffset) { int8_t ret = M2M_ERR_SEND; tstrHifHdr strHif; uint32_t u32CtrlDataGap = u16DataOffset; // while (OSAL_RESULT_FALSE == OSAL_SEM_Pend(&hifSemaphore, OSAL_WAIT_FOREVER)) { } strHif.u8Opcode = u8Opcode&(~NBIT7); strHif.u8Gid = u8Gid; strHif.u16Length = M2M_HIF_HDR_OFFSET; if(pu8CtrlBuf != NULL) { if(u16CtrlBufSize > M2M_HIF_MAX_PACKET_SIZE-M2M_HIF_HDR_OFFSET) { M2M_ERR("HIF %s (%dB) exceeds max (%dB)\n", "Ctrl", u16CtrlBufSize, M2M_HIF_MAX_PACKET_SIZE-M2M_HIF_HDR_OFFSET); goto ERR2; } strHif.u16Length += u16CtrlBufSize; u32CtrlDataGap -= u16CtrlBufSize; } if(pu8DataBuf != NULL) { if((uint32_t)u16DataOffset + u16DataSize > M2M_HIF_MAX_PACKET_SIZE-M2M_HIF_HDR_OFFSET) { M2M_ERR("HIF %s (%luB) exceeds max (%luB)\n", "Data", (uint32_t)u16DataOffset + u16DataSize, (uint32_t)M2M_HIF_MAX_PACKET_SIZE-M2M_HIF_HDR_OFFSET); goto ERR2; } strHif.u16Length += u32CtrlDataGap + u16DataSize; } ret = hif_check_code(strHif.u8Gid, strHif.u8Opcode); if(ret != M2M_SUCCESS) { goto ERR2; } if(strHif.u16Length <= M2M_HIF_MAX_PACKET_SIZE) { ret = hif_chip_wake(); if(ret == M2M_SUCCESS) { volatile uint32_t reg, dma_addr = 0; volatile uint16_t cnt = 0; reg = 0UL; reg |= (uint32_t)u8Gid; reg |= ((uint32_t)u8Opcode<<8); reg |= ((uint32_t)strHif.u16Length<<16); ret = nm_write_reg(NMI_STATE_REG, reg); if(M2M_SUCCESS != ret) goto ERR1; reg = 0UL; reg |= NBIT1; ret = nm_write_reg(WIFI_HOST_RCV_CTRL_2, reg); if(M2M_SUCCESS != ret) goto ERR1; if (ISNMC3400(nmi_get_chipid())) { ret = nm_write_reg(INTERRUPT_CORTUS_1_3000D0, 1); if(M2M_SUCCESS != ret) goto ERR1; } dma_addr = 0; for(cnt = 0; cnt < 1000*5; cnt ++) { ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_2, (uint32_t *)®); if(ret != M2M_SUCCESS) break; /* * If it takes too long to get a response, the slow down to * avoid back-to-back register read operations. */ if(cnt >= 1000) { if(cnt == 1000) { M2M_INFO("Slowing down...\n"); } nm_sleep(5); } if(!(reg & NBIT1)) { ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_4, (uint32_t *)&dma_addr); if(ret != M2M_SUCCESS) { /*in case of read error clear the DMA address and return error*/ dma_addr = 0; goto ERR1; } /*in case of success break */ break; } } if (dma_addr != 0) { volatile uint32_t u32CurrAddr; u32CurrAddr = dma_addr; strHif.u16Length=NM_BSP_B_L_16(strHif.u16Length); M2M_DBG("Writing into %" PRIx32 " %d\r\n", dma_addr, strHif.u16Length); ret = nm_write_block(u32CurrAddr, (uint8_t*)&strHif, M2M_HIF_HDR_OFFSET); if(M2M_SUCCESS != ret) goto ERR1; u32CurrAddr += M2M_HIF_HDR_OFFSET; if(pu8CtrlBuf != NULL) { ret = nm_write_block(u32CurrAddr, pu8CtrlBuf, u16CtrlBufSize); if(M2M_SUCCESS != ret) goto ERR1; u32CurrAddr += u16CtrlBufSize; } if(pu8DataBuf != NULL) { u32CurrAddr += u32CtrlDataGap; ret = nm_write_block(u32CurrAddr, pu8DataBuf, u16DataSize); if(M2M_SUCCESS != ret) goto ERR1; u32CurrAddr += u16DataSize; } reg = dma_addr << 2; /* Following line of code is to generate the interrupt which is not strictly needed for 3400, but has no noticeable side effects */ reg |= NBIT1; ret = nm_write_reg(WIFI_HOST_RCV_CTRL_3, reg); if(M2M_SUCCESS != ret) goto ERR1; if (ISNMC3400(nmi_get_chipid())) { ret = nm_write_reg(INTERRUPT_CORTUS_2_3000D0, 1); if(M2M_SUCCESS != ret) goto ERR1; } } else { ret = hif_chip_sleep(); M2M_DBG("Failed to alloc rx size\r\n"); ret = M2M_ERR_MEM_ALLOC; goto ERR2; } } else { M2M_ERR("(HIF)Failed to wakeup the chip\r\n"); goto ERR2; } } else { M2M_ERR("HIF message length (%d) exceeds max length (%d)\r\n", strHif.u16Length, M2M_HIF_MAX_PACKET_SIZE); ret = M2M_ERR_SEND; goto ERR2; } // OSAL_SEM_Post(&hifSemaphore); /*actual sleep ret = M2M_SUCCESS*/ ret = hif_chip_sleep(); return ret; ERR1: /*reset the count but no actual sleep as it already bus error*/ hif_chip_sleep_sc(); ERR2: /*logical error*/ // OSAL_SEM_Post(&hifSemaphore); return ret; } /** * @fn hif_isr * @brief Host interface interrupt service routine * @return @ref M2M_SUCCESS in case of success or a negative vale otherwise */ static int8_t hif_isr(void) { int8_t ret = M2M_SUCCESS; uint32_t reg; volatile tstrHifHdr strHif; // while (OSAL_RESULT_FALSE == OSAL_SEM_Pend(&hifSemaphore, OSAL_WAIT_FOREVER)) { } ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, ®); if(M2M_SUCCESS == ret) { if(reg & 0x1) /* New interrupt has been received */ { uint16_t size; /*Clearing RX interrupt*/ ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, ®); if(ret != M2M_SUCCESS)goto ERR1; reg &= ~NBIT0; ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0, reg); if(ret != M2M_SUCCESS)goto ERR1; /* read the rx size */ ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, ®); if(M2M_SUCCESS != ret) { M2M_ERR("(hif) WIFI_HOST_RCV_CTRL_0 bus fail\r\n"); goto ERR1; } gstrHifCxt.u8HifRXDone = 1; size = (uint16_t)((reg >> 2) & 0xfff); if (size > 0) { uint32_t address = 0; /** start bus transfer **/ ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_1, &address); if(M2M_SUCCESS != ret) { M2M_ERR("(hif) WIFI_HOST_RCV_CTRL_1 bus fail\r\n"); goto ERR1; } gstrHifCxt.u32RxAddr = address; gstrHifCxt.u32RxSize = size; ret = nm_read_block(address, (uint8_t*)&strHif, sizeof(tstrHifHdr)); strHif.u16Length = NM_BSP_B_L_16(strHif.u16Length); if(M2M_SUCCESS != ret) { M2M_ERR("(hif) address bus fail\r\n"); goto ERR1; } if(strHif.u16Length != size) { if((size - strHif.u16Length) > 4) { M2M_ERR("(hif) Corrupted packet Size = %u \r\n", size, strHif.u16Length, strHif.u8Gid, strHif.u8Opcode); ret = M2M_ERR_BUS_FAIL; goto ERR1; } } // OSAL_SEM_Post(&hifSemaphore); if(M2M_REQ_GROUP_WIFI == strHif.u8Gid) { if(gstrHifCxt.pfWifiCb) gstrHifCxt.pfWifiCb(strHif.u8Opcode, strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); else M2M_ERR("WIFI callback is not registered\r\n"); } else if(M2M_REQ_GROUP_IP == strHif.u8Gid) { if(gstrHifCxt.pfIpCb) gstrHifCxt.pfIpCb(strHif.u8Opcode, strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); else M2M_ERR("Socket callback is not registered\r\n"); } else if(M2M_REQ_GROUP_OTA == strHif.u8Gid) { if(gstrHifCxt.pfOtaCb) gstrHifCxt.pfOtaCb(strHif.u8Opcode, strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); else M2M_ERR("OTA callback is not registered\r\n"); } else if(M2M_REQ_GROUP_SIGMA == strHif.u8Gid) { if(gstrHifCxt.pfSigmaCb) gstrHifCxt.pfSigmaCb(strHif.u8Opcode, strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); else M2M_ERR("Sigma callback is not registered\r\n"); } else if(M2M_REQ_GROUP_SSL == strHif.u8Gid) { if(gstrHifCxt.pfSslCb) gstrHifCxt.pfSslCb(strHif.u8Opcode, strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); else M2M_ERR("SSL callback is not registered\r\n"); } else { M2M_ERR("(hif) invalid group ID\r\n"); return M2M_ERR_BUS_FAIL; } if(gstrHifCxt.u8HifRXDone) { M2M_ERR("(hif) host app didn't set RX Done <%u><%X>\n", strHif.u8Gid, strHif.u8Opcode); return hif_set_rx_done(); } return M2M_SUCCESS; } else { ret = M2M_ERR_RCV; M2M_ERR("(hif) Wrong Size\r\n"); goto ERR1; } } else { M2M_ERR("(hif) False interrupt %lx\r\n",reg); ret = M2M_ERR_FAIL; } } else { M2M_ERR("(hif) Failed to read interrupt reg\r\n"); } ERR1: // OSAL_SEM_Post(&hifSemaphore); return ret; } /** * @fn hif_handle_isr(void) * @brief Handle interrupt received from WINC3400 firmware. * @return The function SHALL return 0 for success and a negative value otherwise. */ int8_t hif_handle_isr(void) { int8_t ret = M2M_SUCCESS; ret = hif_isr(); if (M2M_SUCCESS != ret) { M2M_ERR("(hif) Failed to handle interrupt %d try Again..\r\n",ret); } return ret; } /** * @fn hif_receive * @brief Host interface interrupt service routine * @param[in] u32Addr * Receive start address * @param[out] pu8Buf * Pointer to receive buffer. Allocated by the caller * @param[in] u16Sz * Receive buffer size * @param[in] isDone * If you don't need any more packets send True otherwise send false * @return The function shall return ZERO for successful operation and a negative value otherwise. */ int8_t hif_receive(uint32_t u32Addr, uint8_t *pu8Buf, uint16_t u16Sz, uint8_t isDone) { int8_t ret = M2M_SUCCESS; if((u32Addr == 0) || (pu8Buf == NULL) || (u16Sz == 0)) { if(isDone) { ret = hif_set_rx_done(); } else { ret = M2M_ERR_FAIL; M2M_ERR(" hif_receive: Invalid argument\r\n"); } goto ERR1; } if(u16Sz > gstrHifCxt.u32RxSize) { ret = M2M_ERR_FAIL; M2M_ERR("APP Requested Size is larger than the received buffer size <%d><%" PRId32 ">\r\n", u16Sz, gstrHifCxt.u32RxSize); goto ERR1; } if((u32Addr < gstrHifCxt.u32RxAddr)||((u32Addr + u16Sz)>(gstrHifCxt.u32RxAddr+gstrHifCxt.u32RxSize))) { ret = M2M_ERR_FAIL; M2M_ERR("APP Requested Address beyond the received buffer address and length\r\n"); goto ERR1; } /* Receive the payload */ ret = nm_read_block(u32Addr, pu8Buf, u16Sz); if(ret != M2M_SUCCESS)goto ERR1; /* check if this is the last packet */ if( isDone || (((gstrHifCxt.u32RxAddr+gstrHifCxt.u32RxSize) - (u32Addr+u16Sz)) <= 3) /* Length in the RCV CTRL 0 register is rounded off to 4 by the firmware, but length inside the HIF header is not, hence consider done if fewer than 4 bytes left to read */ ) { /* set RX done */ ret = hif_set_rx_done(); } ERR1: return ret; } /** * @fn hif_register_cb * @brief To set Callback function for every component * @param[in] u8Grp * Group to which the Callback function should be set. * @param[in] fn * function to be set * @return The function shall return ZERO for successful operation and a negative value otherwise. */ int8_t hif_register_cb(uint8_t u8Grp, tpfHifCallBack fn) { int8_t ret = M2M_SUCCESS; switch(u8Grp) { case M2M_REQ_GROUP_IP: gstrHifCxt.pfIpCb = fn; break; case M2M_REQ_GROUP_WIFI: gstrHifCxt.pfWifiCb = fn; break; case M2M_REQ_GROUP_OTA: gstrHifCxt.pfOtaCb = fn; break; case M2M_REQ_GROUP_HIF: gstrHifCxt.pfHifCb = fn; break; case M2M_REQ_GROUP_SIGMA: gstrHifCxt.pfSigmaCb = fn; break; case M2M_REQ_GROUP_SSL: gstrHifCxt.pfSslCb = fn; break; default: M2M_ERR("GRp ? %d\r\n", u8Grp); ret = M2M_ERR_FAIL; break; } return ret; } //DOM-IGNORE-END