857 lines
28 KiB
C
857 lines
28 KiB
C
/*******************************************************************************
|
|
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 <L = %u, G = %u, OP = %02X>\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
|