879 lines
22 KiB
C
879 lines
22 KiB
C
/**
|
|
*
|
|
* \file
|
|
*
|
|
* \brief This module contains M2M host interface APIs implementation.
|
|
*
|
|
* Copyright (c) 2017-2018 Microchip Technology Inc. and its subsidiaries.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* 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.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
*/
|
|
|
|
#include "common/include/nm_common.h"
|
|
#include "driver/source/nmbus.h"
|
|
#include "driver/source/nmdrv.h"
|
|
#include "bsp/include/nm_bsp.h"
|
|
#include "m2m_hif.h"
|
|
#include "driver/include/m2m_types.h"
|
|
#include "driver/source/nmasic.h"
|
|
#include "driver/include/m2m_periph.h"
|
|
|
|
#if (defined NM_EDGE_INTERRUPT)&&(defined NM_LEVEL_INTERRUPT)
|
|
#error "only one type of interrupt NM_EDGE_INTERRUPT,NM_LEVEL_INTERRUPT"
|
|
#endif
|
|
|
|
#if !((defined NM_EDGE_INTERRUPT)||(defined NM_LEVEL_INTERRUPT))
|
|
#error "define interrupt type NM_EDGE_INTERRUPT,NM_LEVEL_INTERRUPT"
|
|
#endif
|
|
|
|
#ifndef CORTUS_APP
|
|
#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 WAKE_VALUE (0x5678)
|
|
#define SLEEP_VALUE (0x4321)
|
|
#define WAKE_REG (0x1074)
|
|
|
|
#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 volatile uint8 gu8ChipMode = 0;
|
|
static volatile uint8 gu8ChipSleep = 0;
|
|
static volatile uint8 gu8HifSizeDone = 0;
|
|
static volatile uint8 gu8Interrupt = 0;
|
|
static volatile uint8 gu8Yield = 0;
|
|
|
|
/*
|
|
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)
|
|
#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)
|
|
/*
|
|
List of new HIF messages (since last HIF major increase)
|
|
Each entry is formed of ((GroupId << 8) | OpCode)
|
|
Additionally, entry 0 used to indicate OTA RB/SW only.
|
|
*/
|
|
#define NEW_HIF_LIST HIF_OTA_RB_ONLY, HIFCODE_SSL_WRITECERT, HIFCODE_WIFI_PASSIVESCAN
|
|
/*
|
|
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 gau16HifBlacklist[] = {NEW_HIF_LIST};
|
|
#define HIF_BLACKLIST_SZ (sizeof(gau16HifBlacklist)/sizeof(gau16HifBlacklist[0]))
|
|
static uint8 gu8HifBlOffset = 0;
|
|
|
|
tpfHifCallBack pfWifiCb = NULL; /*!< pointer to Wi-Fi call back function */
|
|
tpfHifCallBack pfIpCb = NULL; /*!< pointer to Socket call back function */
|
|
tpfHifCallBack pfOtaCb = NULL; /*!< pointer to OTA call back function */
|
|
tpfHifCallBack pfSigmaCb = NULL;
|
|
tpfHifCallBack pfHifCb = NULL;
|
|
tpfHifCallBack pfSSLCb = NULL;
|
|
|
|
static void isr(void)
|
|
{
|
|
gu8Interrupt++;
|
|
#ifdef NM_LEVEL_INTERRUPT
|
|
nm_bsp_interrupt_ctrl(0);
|
|
#endif
|
|
}
|
|
|
|
static sint8 hif_set_rx_done(void)
|
|
{
|
|
uint32 reg;
|
|
sint8 ret = M2M_SUCCESS;
|
|
#ifdef NM_EDGE_INTERRUPT
|
|
nm_bsp_interrupt_ctrl(1);
|
|
#endif
|
|
|
|
|
|
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;
|
|
//reg &= ~(1<<0);
|
|
|
|
/* Set RX Done */
|
|
reg |= (1<<1);
|
|
ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0,reg);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
}
|
|
|
|
#ifdef NM_LEVEL_INTERRUPT
|
|
nm_bsp_interrupt_ctrl(1);
|
|
#endif
|
|
ERR1:
|
|
return ret;
|
|
|
|
}
|
|
/**
|
|
* @fn static void m2m_hif_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr)
|
|
* @brief WiFi call back function
|
|
* @param [in] u8OpCode
|
|
* HIF Opcode type.
|
|
* @param [in] u16DataSize
|
|
* HIF data length.
|
|
* @param [in] u32Addr
|
|
* HIF address.
|
|
* @author
|
|
* @date
|
|
* @version 1.0
|
|
*/
|
|
static void m2m_hif_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr)
|
|
{
|
|
|
|
|
|
}
|
|
/**
|
|
* @fn NMI_API sint8 hif_chip_wake(void);
|
|
* @brief To Wakeup the chip.
|
|
* @return The function shall return ZERO for successful operation and a negative value otherwise.
|
|
*/
|
|
|
|
sint8 hif_chip_wake(void)
|
|
{
|
|
sint8 ret = M2M_SUCCESS;
|
|
if(gu8ChipSleep == 0)
|
|
{
|
|
if((gu8ChipMode == M2M_PS_DEEP_AUTOMATIC)||(gu8ChipMode == M2M_PS_MANUAL))
|
|
{
|
|
ret = nm_clkless_wake();
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
ret = nm_write_reg(WAKE_REG, WAKE_VALUE);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
gu8ChipSleep++;
|
|
ERR1:
|
|
return ret;
|
|
}
|
|
/*!
|
|
@fn \
|
|
NMI_API void hif_set_sleep_mode(uint8 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 u8Pstype)
|
|
{
|
|
gu8ChipMode = u8Pstype;
|
|
}
|
|
/*!
|
|
@fn \
|
|
NMI_API uint8 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 hif_get_sleep_mode(void)
|
|
{
|
|
return gu8ChipMode;
|
|
}
|
|
/**
|
|
* @fn NMI_API sint8 hif_chip_sleep(void);
|
|
* @brief To make the chip sleep.
|
|
* @return The function shall return ZERO for successful operation and a negative value otherwise.
|
|
*/
|
|
|
|
sint8 hif_chip_sleep(void)
|
|
{
|
|
|
|
sint8 ret = M2M_SUCCESS;
|
|
|
|
if(gu8ChipSleep >= 1)
|
|
{
|
|
gu8ChipSleep--;
|
|
}
|
|
|
|
if(gu8ChipSleep == 0)
|
|
{
|
|
if((gu8ChipMode == M2M_PS_DEEP_AUTOMATIC)||(gu8ChipMode == M2M_PS_MANUAL))
|
|
{
|
|
uint32 reg = 0;
|
|
ret = nm_write_reg(WAKE_REG, SLEEP_VALUE);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
/* Clear bit 1 */
|
|
ret = nm_read_reg_with_ret(0x1, ®);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
if(reg&0x2)
|
|
{
|
|
reg &=~(1 << 1);
|
|
ret = nm_write_reg(0x1, reg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
ERR1:
|
|
return ret;
|
|
}
|
|
/**
|
|
* @fn NMI_API sint8 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.
|
|
*/
|
|
|
|
sint8 hif_init(void * arg)
|
|
{
|
|
pfWifiCb = NULL;
|
|
pfIpCb = NULL;
|
|
|
|
gu8ChipSleep = 0;
|
|
gu8ChipMode = M2M_NO_PS;
|
|
|
|
gu8Interrupt = 0;
|
|
nm_bsp_register_isr(isr);
|
|
|
|
gu8HifBlOffset = 0;
|
|
hif_register_cb(M2M_REQ_GROUP_HIF,m2m_hif_cb);
|
|
|
|
return M2M_SUCCESS;
|
|
}
|
|
/**
|
|
* @fn NMI_API sint8 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.
|
|
*/
|
|
sint8 hif_deinit(void * arg)
|
|
{
|
|
sint8 ret = M2M_SUCCESS;
|
|
#if 0
|
|
uint32 reg = 0, cnt=0;
|
|
while (reg != M2M_DISABLE_PS)
|
|
{
|
|
nm_bsp_sleep(1);
|
|
reg = nm_read_reg(STATE_REG);
|
|
if(++cnt > 1000)
|
|
{
|
|
M2M_DBG("failed to stop power save\n");
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
ret = hif_chip_wake();
|
|
|
|
gu8ChipMode = 0;
|
|
gu8ChipSleep = 0;
|
|
gu8HifSizeDone = 0;
|
|
gu8Interrupt = 0;
|
|
|
|
pfWifiCb = NULL;
|
|
pfIpCb = NULL;
|
|
pfOtaCb = NULL;
|
|
pfHifCb = NULL;
|
|
|
|
return ret;
|
|
}
|
|
/**
|
|
* @fn sint8 hif_check_compatibility(uint16 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.
|
|
*/
|
|
sint8 hif_check_compatibility(uint16 u16HifInfo)
|
|
{
|
|
sint8 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 sint8 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.
|
|
*/
|
|
sint8 hif_enable_access(void)
|
|
{
|
|
sint8 ret = M2M_SUCCESS;
|
|
uint16 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;
|
|
// 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\n");
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
/**
|
|
* @fn sint8 hif_check_code(uint8 u8Gid, uint8 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 ZERO for support and a negative value otherwise.
|
|
*/
|
|
sint8 hif_check_code(uint8 u8Gid, uint8 u8OpCode)
|
|
{
|
|
uint8 u8BlId;
|
|
uint16 u16HifCode = ((uint16)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\n");
|
|
return M2M_ERR_SEND;
|
|
}
|
|
for(u8BlId = gu8HifBlOffset; u8BlId < HIF_BLACKLIST_SZ; u8BlId++)
|
|
{
|
|
if(u16HifCode == gau16HifBlacklist[u8BlId])
|
|
{
|
|
M2M_ERR("HIF message unsupported\n");
|
|
return M2M_ERR_SEND;
|
|
}
|
|
}
|
|
return M2M_SUCCESS;
|
|
}
|
|
/**
|
|
* @fn NMI_API sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize,
|
|
uint8 *pu8DataBuf,uint16 u16DataSize, uint16 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 ZERO for successful operation and a negative value otherwise.
|
|
*/
|
|
|
|
sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize,
|
|
uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset)
|
|
{
|
|
sint8 ret = M2M_ERR_SEND;
|
|
volatile tstrHifHdr strHif;
|
|
|
|
strHif.u8Opcode = u8Opcode&(~NBIT7);
|
|
strHif.u8Gid = u8Gid;
|
|
strHif.u16Length = M2M_HIF_HDR_OFFSET;
|
|
if(pu8DataBuf != NULL)
|
|
{
|
|
strHif.u16Length += u16DataOffset + u16DataSize;
|
|
}
|
|
else
|
|
{
|
|
strHif.u16Length += u16CtrlBufSize;
|
|
}
|
|
|
|
ret = hif_check_code(strHif.u8Gid, strHif.u8Opcode);
|
|
if(ret != M2M_SUCCESS)
|
|
{
|
|
goto ERR1;
|
|
}
|
|
|
|
ret = hif_chip_wake();
|
|
if(ret == M2M_SUCCESS)
|
|
{
|
|
volatile uint32 reg, dma_addr = 0;
|
|
volatile uint16 cnt = 0;
|
|
|
|
reg = 0UL;
|
|
reg |= (uint32)u8Gid;
|
|
reg |= ((uint32)u8Opcode<<8);
|
|
reg |= ((uint32)strHif.u16Length<<16);
|
|
ret = nm_write_reg(NMI_STATE_REG,reg);
|
|
if(M2M_SUCCESS != ret) goto ERR1;
|
|
|
|
reg = 0;
|
|
reg |= (1<<1);
|
|
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;
|
|
|
|
//nm_bsp_interrupt_ctrl(0);
|
|
|
|
for(cnt = 0; cnt < 1000*5; cnt ++)
|
|
{
|
|
ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_2,(uint32 *)®);
|
|
if(ret != M2M_SUCCESS)
|
|
break;
|
|
|
|
if (!(reg & 0x2))
|
|
{
|
|
ret = nm_read_reg_with_ret(0x150400,(uint32 *)&dma_addr);
|
|
if(ret != M2M_SUCCESS) {
|
|
/*in case of read error clear the dma address and return error*/
|
|
dma_addr = 0;
|
|
}
|
|
/*in case of success break */
|
|
break;
|
|
}
|
|
//If we are struggling to get a response, start waiting longer
|
|
if (cnt>=1000)
|
|
nm_bsp_sleep(5);
|
|
}
|
|
//nm_bsp_interrupt_ctrl(1);
|
|
|
|
if (dma_addr != 0)
|
|
{
|
|
volatile uint32 u32CurrAddr;
|
|
u32CurrAddr = dma_addr;
|
|
strHif.u16Length=NM_BSP_B_L_16(strHif.u16Length);
|
|
M2M_DBG("Writing into %lx %ld\n", dma_addr, strHif.u16Length);
|
|
ret = nm_write_block(u32CurrAddr, (uint8*)&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 += (u16DataOffset - u16CtrlBufSize);
|
|
ret = nm_write_block(u32CurrAddr, pu8DataBuf, u16DataSize);
|
|
if(M2M_SUCCESS != ret)
|
|
goto ERR1;
|
|
u32CurrAddr += u16DataSize;
|
|
}
|
|
|
|
reg = dma_addr << 2;
|
|
|
|
/* MERGEBUG: TODO: Following line of code is to generate the interrupt which
|
|
is not needed for 3400, need to check if there are any side effects of keeping it
|
|
*/
|
|
reg |= (1 << 1);
|
|
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
|
|
{
|
|
M2M_DBG("Failed to alloc rx size\n");
|
|
ret = M2M_ERR_MEM_ALLOC;
|
|
goto ERR1;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
M2M_ERR("(HIF)Fail to wakup the chip\n");
|
|
goto ERR1;
|
|
}
|
|
ret = hif_chip_sleep();
|
|
|
|
ERR1:
|
|
return ret;
|
|
}
|
|
/**
|
|
* @fn hif_isr
|
|
* @brief Host interface interrupt service routine
|
|
* @author M. Abdelmawla
|
|
* @date 15 July 2012
|
|
* @return 1 in case of interrupt received else 0 will be returned
|
|
* @version 1.0
|
|
*/
|
|
static sint8 hif_isr(void)
|
|
{
|
|
sint8 ret = M2M_SUCCESS;
|
|
uint32 reg;
|
|
volatile tstrHifHdr strHif;
|
|
|
|
|
|
//if(ret == M2M_SUCCESS)
|
|
{
|
|
ret = nm_read_reg_with_ret(0x1070, ®);
|
|
if(M2M_SUCCESS == ret)
|
|
{
|
|
if(reg & 0x1) /* New interrupt has been received */
|
|
{
|
|
uint16 size;
|
|
|
|
nm_bsp_interrupt_ctrl(0);
|
|
/*Clearing RX interrupt*/
|
|
ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0,®);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
reg &= ~(1<<0);
|
|
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\n");
|
|
nm_bsp_interrupt_ctrl(1);
|
|
goto ERR1;
|
|
}
|
|
gu8HifSizeDone = 0;
|
|
size = (uint16)((reg >> 2) & 0xfff);
|
|
if (size > 0) {
|
|
uint32 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\n");
|
|
nm_bsp_interrupt_ctrl(1);
|
|
goto ERR1;
|
|
}
|
|
ret = nm_read_block(address, (uint8*)&strHif, sizeof(tstrHifHdr));
|
|
strHif.u16Length = NM_BSP_B_L_16(strHif.u16Length);
|
|
if(M2M_SUCCESS != ret)
|
|
{
|
|
M2M_ERR("(hif) address bus fail\n");
|
|
nm_bsp_interrupt_ctrl(1);
|
|
goto ERR1;
|
|
}
|
|
if(strHif.u16Length != size)
|
|
{
|
|
if((size - strHif.u16Length) > 4)
|
|
{
|
|
M2M_ERR("(hif) Corrupted packet Size = %u <L = %u, G = %u, OP = %02X>\n",
|
|
size, strHif.u16Length, strHif.u8Gid, strHif.u8Opcode);
|
|
nm_bsp_interrupt_ctrl(1);
|
|
ret = M2M_ERR_BUS_FAIL;
|
|
goto ERR1;
|
|
}
|
|
}
|
|
|
|
if(M2M_REQ_GROUP_WIFI == strHif.u8Gid)
|
|
{
|
|
if(pfWifiCb)
|
|
pfWifiCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
|
|
|
|
}
|
|
else if(M2M_REQ_GROUP_IP == strHif.u8Gid)
|
|
{
|
|
if(pfIpCb)
|
|
pfIpCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
|
|
}
|
|
else if(M2M_REQ_GROUP_OTA == strHif.u8Gid)
|
|
{
|
|
if(pfOtaCb)
|
|
pfOtaCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
|
|
}
|
|
else if(M2M_REQ_GROUP_SIGMA == strHif.u8Gid)
|
|
{
|
|
if(pfSigmaCb)
|
|
pfSigmaCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
|
|
}
|
|
else if(M2M_REQ_GROUP_SSL == strHif.u8Gid)
|
|
{
|
|
if(pfSSLCb)
|
|
pfSSLCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET);
|
|
}
|
|
else
|
|
{
|
|
M2M_ERR("(hif) invalid group ID\n");
|
|
ret = M2M_ERR_BUS_FAIL;
|
|
goto ERR1;
|
|
}
|
|
#ifndef ENABLE_UNO_BOARD
|
|
if(!gu8HifSizeDone)
|
|
{
|
|
M2M_ERR("(hif) host app didn't set RX Done\n");
|
|
ret = hif_set_rx_done();
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ret = M2M_ERR_RCV;
|
|
M2M_ERR("(hif) Wrong Size\n");
|
|
goto ERR1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifndef WIN32
|
|
M2M_ERR("(hif) False interrupt %lx",reg);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M2M_ERR("(hif) Fail to Read interrupt reg\n");
|
|
}
|
|
}
|
|
|
|
ERR1:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @fn hif_handle_isr(void)
|
|
* @brief Handle interrupt received from NMC1500 firmware.
|
|
* @return The function SHALL return 0 for success and a negative value otherwise.
|
|
*/
|
|
|
|
void hif_yield(void)
|
|
{
|
|
gu8Yield = 1;
|
|
}
|
|
|
|
sint8 hif_handle_isr(void)
|
|
{
|
|
sint8 ret = M2M_SUCCESS;
|
|
|
|
if (gu8Interrupt) {
|
|
ret = hif_chip_wake();
|
|
// Sleep(10);
|
|
if(ret == M2M_SUCCESS)
|
|
{
|
|
gu8Yield = 0;
|
|
while (gu8Interrupt && !gu8Yield) {
|
|
/*must be at that place because of the race of interrupt increment and that decrement*/
|
|
/*when the interrupt enabled*/
|
|
gu8Interrupt--;
|
|
while(1)
|
|
{
|
|
ret = hif_isr();
|
|
if(ret == M2M_SUCCESS/* || gu8Interrupt == 0*/) { //JFM: WTF un while(1)!!!!!
|
|
/*we will try forever until we get that interrupt*/
|
|
/*Fail return errors here due to bus errors (reading expected values)*/
|
|
break;
|
|
} else {
|
|
M2M_ERR("(HIF) Fail to handle interrupt %d try Again..\n",ret);
|
|
}
|
|
}
|
|
}
|
|
ret = hif_chip_sleep();
|
|
}
|
|
else {
|
|
M2M_ERR("(hif) FAIL to wakeup the chip\n");
|
|
}
|
|
}
|
|
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.
|
|
*/
|
|
sint8 hif_receive(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz, uint8 isDone)
|
|
{
|
|
uint32 address, reg;
|
|
uint16 size;
|
|
sint8 ret = M2M_SUCCESS;
|
|
|
|
if(u32Addr == 0 || pu8Buf == NULL || u16Sz == 0)
|
|
{
|
|
if(isDone)
|
|
{
|
|
gu8HifSizeDone = 1;
|
|
|
|
/* set RX done */
|
|
ret = hif_set_rx_done();
|
|
|
|
if((u32Addr == 0) && (pu8Buf == NULL) && (u16Sz == 0))
|
|
return M2M_SUCCESS;
|
|
}
|
|
|
|
ret = M2M_ERR_FAIL;
|
|
M2M_ERR(" hif_receive: Invalid argument\n");
|
|
goto ERR1;
|
|
}
|
|
|
|
ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0,®);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
|
|
|
|
size = (uint16)((reg >> 2) & 0xfff);
|
|
ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_1,&address);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
|
|
/* Receive the payload */
|
|
ret = nm_read_block(u32Addr, pu8Buf, u16Sz);
|
|
if(ret != M2M_SUCCESS)goto ERR1;
|
|
|
|
if(u16Sz > size)
|
|
{
|
|
ret = M2M_ERR_FAIL;
|
|
M2M_ERR("APP Requested Size is larger than the recived buffer size <%d><%d>\n",u16Sz, size);
|
|
goto ERR1;
|
|
}
|
|
if((u32Addr < address)||((u32Addr + u16Sz)>(address+size)))
|
|
{
|
|
ret = M2M_ERR_FAIL;
|
|
M2M_ERR("APP Requested Address beyond the recived buffer address and length\n");
|
|
goto ERR1;
|
|
}
|
|
|
|
/* check if this is the last packet */
|
|
if(isDone || (((address+size) - (u32Addr+u16Sz)) == 0) ||
|
|
((4 - ((u32Addr+u16Sz) & 3)) == ((address+size) - (u32Addr+u16Sz)))) /* 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 number
|
|
of rounding bytes equal to length left to read */
|
|
{
|
|
gu8HifSizeDone = 1;
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
sint8 hif_register_cb(uint8 u8Grp,tpfHifCallBack fn)
|
|
{
|
|
sint8 ret = M2M_SUCCESS;
|
|
switch(u8Grp)
|
|
{
|
|
case M2M_REQ_GROUP_IP:
|
|
pfIpCb = fn;
|
|
break;
|
|
case M2M_REQ_GROUP_WIFI:
|
|
pfWifiCb = fn;
|
|
break;
|
|
case M2M_REQ_GROUP_OTA:
|
|
pfOtaCb = fn;
|
|
break;
|
|
case M2M_REQ_GROUP_HIF:
|
|
pfHifCb = fn;
|
|
break;
|
|
case M2M_REQ_GROUP_SIGMA:
|
|
pfSigmaCb = fn;
|
|
break;
|
|
case M2M_REQ_GROUP_SSL:
|
|
pfSSLCb = fn;
|
|
break;
|
|
default:
|
|
M2M_ERR("GRp ? %d\n",u8Grp);
|
|
ret = M2M_ERR_FAIL;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif
|