TI's CC3100. A test demo with very little testing done!
Fork of cc3100_Test_Demo2 by
Diff: simplelink/cc3100.cpp
- Revision:
- 6:778b081f6a13
- Child:
- 8:bb9cccbe84d7
diff -r d3b320ebd469 -r 778b081f6a13 simplelink/cc3100.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/simplelink/cc3100.cpp Thu Mar 19 15:39:08 2015 +0000 @@ -0,0 +1,1338 @@ +/* +* device.c - CC31xx/CC32xx Host Driver Implementation +* +* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ +* +* +* 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. +* +*/ + + + +/*****************************************************************************/ +/* Include files */ +/*****************************************************************************/ +#include "cc3100_simplelink.h" +#include "cc3100_protocol.h" +#include "cc3100_sl_common.h" +#include "cc3100.h" + +#include "fPtr_func.h" + + +namespace mbed_cc3100 { + + uint32_t g_PingPacketsRecv; + uint32_t g_GatewayIP; + uint32_t g_StationIP; + uint32_t g_DestinationIP; + uint32_t g_BytesReceived; // variable to store the file size + uint32_t g_Status; + uint8_t g_buff[MAX_BUFF_SIZE+1]; + int32_t g_SockID; + + +cc3100::cc3100(PinName cc3100_irq, PinName cc3100_nHIB, PinName cc3100_cs, SPI cc3100_spi) + : _spi(cc3100_irq, cc3100_nHIB, cc3100_cs, cc3100_spi, _driver), + _driver(_nonos, _netapp, _flowcont, _spi), _nonos(_driver), _wlan(_driver, _wlan_filters), + _wlan_filters(_driver), _netapp(_driver, _nonos), _fs(_driver), _netcfg(_driver), + _socket(_driver, _nonos), _flowcont(_driver, _nonos) + + +{ + +} + +cc3100::~cc3100() +{ + +} + +/*! + \brief This function initializes the application variables + + \param[in] None + + \return 0 on success, negative error-code on error +*/ +int32_t cc3100::initializeAppVariables() +{ + + g_Status = 0; + g_PingPacketsRecv = 0; + g_StationIP = 0; + g_GatewayIP = 0; + g_DestinationIP = 0; + g_BytesReceived = 0; /* variable to store the file size */ + g_SockID = 0; + memset(g_buff, 0, sizeof(g_buff)); + + return SUCCESS; +} + +/*! + \brief Disconnecting from a WLAN Access point + + This function disconnects from the connected AP + + \param[in] None + + \return none + + \note + + \warning If the WLAN disconnection fails, we will be stuck in this function forever. +*/ +int32_t cc3100::disconnectFromAP() +{ + int32_t retVal = -1; + + /* + * The function returns 0 if 'Disconnected done', negative number if already disconnected + * Wait for 'disconnection' event if 0 is returned, Ignore other return-codes + */ + retVal = _wlan.sl_WlanDisconnect(); + if(0 == retVal) + { + /* Wait */ + while(IS_CONNECTED(g_Status,STATUS_BIT_CONNECTION)) { _nonos._SlNonOsMainLoopTask(); } + } + + return SUCCESS; +} + +/*! + \brief This function configure the SimpleLink device in its default state. It: + - Sets the mode to STATION + - Configures connection policy to Auto and AutoSmartConfig + - Deletes all the stored profiles + - Enables DHCP + - Disables Scan policy + - Sets Tx power to maximum + - Sets power policy to normal + - Unregisters mDNS services + - Remove all filters + + \param[in] none + + \return On success, zero is returned. On error, negative is returned +*/ +int32_t cc3100::configureSimpleLinkToDefaultState() +{ + SlVersionFull ver = {0}; + _WlanRxFilterOperationCommandBuff_t RxFilterIdMask = {0}; + + uint8_t val = 1; + uint8_t configOpt = 0; + uint8_t configLen = 0; + uint8_t power = 0; + + int32_t retVal = -1; + int32_t role = -1; + + role = sl_Start(0, 0, 0); + ASSERT_ON_ERROR(role); + + /* If the device is not in station-mode, try configuring it in station-mode */ + if (ROLE_STA != role) { + if (ROLE_AP == role) { + /* If the device is in AP mode, we need to wait for this event before doing anything */ + while(!IS_IP_ACQUIRED(g_Status,STATUS_BIT_IP_ACQUIRED)) { + _nonos._SlNonOsMainLoopTask(); + } + } + + /* Switch to STA role and restart */ + retVal = _wlan.sl_WlanSetMode(ROLE_STA); + ASSERT_ON_ERROR(retVal); + + retVal = sl_Stop(SL_STOP_TIMEOUT); + ASSERT_ON_ERROR(retVal); + + retVal = sl_Start(0, 0, 0); + ASSERT_ON_ERROR(retVal); + + /* Check if the device is in station again */ + if (ROLE_STA != retVal) { + /* We don't want to proceed if the device is not coming up in station-mode */ + ASSERT_ON_ERROR(DEVICE_NOT_IN_STATION_MODE); + } + } + + /* Get the device's version-information */ + configOpt = SL_DEVICE_GENERAL_VERSION; + configLen = sizeof(ver); + retVal = sl_DevGet(SL_DEVICE_GENERAL_CONFIGURATION, &configOpt, &configLen, (uint8_t *)(&ver)); + ASSERT_ON_ERROR(retVal); + + /* Set connection policy to Auto + SmartConfig (Device's default connection policy) */ + retVal = _wlan.sl_WlanPolicySet(SL_POLICY_CONNECTION, SL_CONNECTION_POLICY(1, 0, 0, 0, 1), NULL, 0); + ASSERT_ON_ERROR(retVal); + + /* Remove all profiles */ + retVal = _wlan.sl_WlanProfileDel(0xFF); + ASSERT_ON_ERROR(retVal); + + /* + * Device in station-mode. Disconnect previous connection if any + * The function returns 0 if 'Disconnected done', negative number if already disconnected + * Wait for 'disconnection' event if 0 is returned, Ignore other return-codes + */ + retVal = _wlan.sl_WlanDisconnect(); + if(0 == retVal) { + /* Wait */ + while(IS_CONNECTED(g_Status,STATUS_BIT_CONNECTION)) { + _nonos._SlNonOsMainLoopTask(); + } + } + + /* Enable DHCP client*/ + retVal = _netcfg.sl_NetCfgSet(SL_IPV4_STA_P2P_CL_DHCP_ENABLE,1,1,&val); + ASSERT_ON_ERROR(retVal); + + /* Disable scan */ + configOpt = SL_SCAN_POLICY(0); + retVal = _wlan.sl_WlanPolicySet(SL_POLICY_SCAN , configOpt, NULL, 0); + ASSERT_ON_ERROR(retVal); + + /* Set Tx power level for station mode + Number between 0-15, as dB offset from maximum power - 0 will set maximum power */ + power = 0; + retVal = _wlan.sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, 1, (uint8_t *)&power); + ASSERT_ON_ERROR(retVal); + + /* Set PM policy to normal */ + retVal = _wlan.sl_WlanPolicySet(SL_POLICY_PM , SL_NORMAL_POLICY, NULL, 0); + ASSERT_ON_ERROR(retVal); + + /* Unregister mDNS services */ + retVal = _netapp.sl_NetAppMDNSUnRegisterService(0, 0); + ASSERT_ON_ERROR(retVal); + + /* Remove all 64 filters (8*8) */ + memset(RxFilterIdMask.FilterIdMask, 0xFF, 8); + retVal = _wlan_filters.sl_WlanRxFilterSet(SL_REMOVE_RX_FILTER, (uint8_t *)&RxFilterIdMask, + sizeof(_WlanRxFilterOperationCommandBuff_t)); + ASSERT_ON_ERROR(retVal); + + retVal = sl_Stop(SL_STOP_TIMEOUT); + ASSERT_ON_ERROR(retVal); + + retVal = initializeAppVariables(); + ASSERT_ON_ERROR(retVal); + + return retVal; /* Success */ +} + +/*! + \brief Create UDP socket to communicate with server. + + \param[in] none + + \return Socket descriptor for success otherwise negative + + \warning +*/ +int32_t cc3100::createUDPConnection() +{ + int32_t sd = 0; + + sd = _socket.sl_Socket(SL_AF_INET, SL_SOCK_DGRAM, IPPROTO_UDP); + if( sd < 0 ) + { + printf("Error creating socket\n\r\n\r"); + } + + return sd; +} + +/*! + \brief Create connection with server. + + This function opens a socket and create the endpoint communication with server + + \param[in] DestinationIP - IP address of the server + + \return socket id for success and negative for error +*/ +int32_t cc3100::createConnection(uint32_t DestinationIP) +{ + SlSockAddrIn_t Addr = {0}; + int32_t Status = 0; + int32_t AddrSize = 0; + int32_t SockID = 0; + + Addr.sin_family = SL_AF_INET; + Addr.sin_port = _socket.sl_Htons(80); + Addr.sin_addr.s_addr = _socket.sl_Htonl(DestinationIP); + + AddrSize = sizeof(SlSockAddrIn_t); + + SockID = _socket.sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0); + ASSERT_ON_ERROR(SockID); + + Status = _socket.sl_Connect(SockID, ( SlSockAddr_t *)&Addr, AddrSize); + if (Status < 0) + { + _socket.sl_Close(SockID); + ASSERT_ON_ERROR(Status); + } + + return SockID; +} + +/*! + \brief Convert hex to decimal base + + \param[in] ptr - pointer to string containing number in hex + + \return number in decimal base + +*/ +int32_t cc3100::hexToi(unsigned char *ptr) +{ + uint32_t result = 0; + uint32_t len = 0; + + int32_t idx = -1; + + len = strlen((const char*) ptr); + + /* convert characters to upper case */ + for(idx = 0; ptr[idx] != '\0'; ++idx) + { + if( (ptr[idx] >= 'a') && + (ptr[idx] <= 'f') ) + { + ptr[idx] -= 32; /* Change case - ASCII 'a' = 97, 'A' = 65 => 97-65 = 32 */ + } + } + + for(idx = 0; ptr[idx] != '\0'; ++idx) + { + if(ptr[idx] >= '0' && ptr[idx] <= '9') + { + /* Converting '0' to '9' to their decimal value */ + result += (ptr[idx] - '0') * (1 << (4 * (len - 1 - idx))); + } + else if(ptr[idx] >= 'A' && ptr[idx] <= 'F') + { + /* Converting hex 'A' to 'F' to their decimal value */ + result += (ptr[idx] - 55) * (1 << (4 * (len -1 - idx))); /* .i.e. 'A' - 55 = 10, 'F' - 55 = 15 */ + } + else + { + ASSERT_ON_ERROR(INVALID_HEX_STRING); + } + } + + return result; +} + +/*! + \brief Calculate the file chunk size + + \param[in] len - pointer to length of the data in the buffer + \param[in] p_Buff - pointer to pointer of buffer containing data + \param[out] chunk_size - pointer to variable containing chunk size + + \return 0 for success, -ve for error + +*/ +int32_t cc3100::getChunkSize(int32_t *len, uint8_t **p_Buff, uint32_t *chunk_size) +{ + int32_t idx = -1; + unsigned char lenBuff[10]; + + idx = 0; + memset(lenBuff, 0, sizeof(lenBuff)); + while(*len >= 0 && **p_Buff != 13) /* check for <CR> */ + { + if(0 == *len) + { + memset(g_buff, 0, sizeof(g_buff)); + *len = _socket.sl_Recv(g_SockID, &g_buff[0], MAX_BUFF_SIZE, 0); + if(*len <= 0) + ASSERT_ON_ERROR(TCP_RECV_ERROR); + + *p_Buff = g_buff; + } + + lenBuff[idx] = **p_Buff; + idx++; + (*p_Buff)++; + (*len)--; + } + + (*p_Buff) += 2; /* skip <CR><LF> */ + (*len) -= 2; + *chunk_size = hexToi(lenBuff); + + return SUCCESS; +} + +/*! + \brief Obtain the file from the server + + This function requests the file from the server and save it on serial flash. + To request a different file for different user needs to modify the + PREFIX_BUFFER and POST_BUFFER macros. + + \param[in] None + + \return 0 for success and negative for error + +*/ +/* +int32_t cc3100::getFile() +{ + uint32_t Token = 0; + uint32_t recv_size = 0; + uint8_t *pBuff = 0; + uint8_t eof_detected = 0; + uint8_t isChunked = 0; + + int32_t transfer_len = -1; + int32_t retVal = -1; + int32_t fileHandle = -1; + + memset(g_buff, 0, sizeof(g_buff)); + + //Puts together the HTTP GET string. + strcpy((char*)g_buff, PREFIX_BUFFER); + strcat((char*)g_buff, POST_BUFFER); + + //Send the HTTP GET string to the opened TCP/IP socket. + transfer_len = _socket.sl_Send(g_SockID, g_buff, strlen((const char*)g_buff), 0); + + if (transfer_len < 0) + { + // error + printf(" Socket Send Error\r\n"); + ASSERT_ON_ERROR(TCP_SEND_ERROR); + } + + memset(g_buff, 0, sizeof(g_buff)); + + //get the reply from the server in buffer. + transfer_len = _socket.sl_Recv(g_SockID, &g_buff[0], MAX_BUFF_SIZE, 0); + + if(transfer_len <= 0) + ASSERT_ON_ERROR(TCP_RECV_ERROR); + + // Check for 404 return code + if(strstr((const char*)g_buff, HTTP_FILE_NOT_FOUND) != 0) + { + printf(" File not found, check the file and try again\r\n"); + ASSERT_ON_ERROR(FILE_NOT_FOUND_ERROR); + } + + // if not "200 OK" return error + if(strstr((const char*)g_buff, HTTP_STATUS_OK) == 0) + { + printf(" Error during downloading the file\r\n"); + ASSERT_ON_ERROR(INVALID_SERVER_RESPONSE); + } + + // check if content length is transferred with headers + pBuff = (uint8_t *)strstr((const char*)g_buff, HTTP_CONTENT_LENGTH); + if(pBuff != 0) + { + // not supported + printf(" Server response format is not supported\r\n"); + ASSERT_ON_ERROR(FORMAT_NOT_SUPPORTED); + } + + // Check if data is chunked + pBuff = (uint8_t *)strstr((const char*)g_buff, HTTP_TRANSFER_ENCODING); + if(pBuff != 0) + { + pBuff += strlen(HTTP_TRANSFER_ENCODING); + while(*pBuff == SPACE) + pBuff++; + + if(memcmp(pBuff, HTTP_ENCODING_CHUNKED, strlen(HTTP_ENCODING_CHUNKED)) == 0) + { + recv_size = 0; + isChunked = 1; + } + } + else + { + // Check if connection will be closed by after sending data + // In this method the content length is not received and end of + // connection marks the end of data + pBuff = (uint8_t *)strstr((const char*)g_buff, HTTP_CONNECTION); + if(pBuff != 0) + { + pBuff += strlen(HTTP_CONNECTION); + while(*pBuff == SPACE) + pBuff++; + + if(memcmp(pBuff, HTTP_ENCODING_CHUNKED, strlen(HTTP_CONNECTION_CLOSE)) == 0) + { + // not supported + printf(" Server response format is not supported\r\n"); + ASSERT_ON_ERROR(FORMAT_NOT_SUPPORTED); + } + } + } + + // "\r\n\r\n" marks the end of headers + pBuff = (uint8_t *)strstr((const char*)g_buff, HTTP_END_OF_HEADER); + if(pBuff == 0) + { + printf(" Invalid response\r\n"); + ASSERT_ON_ERROR(INVALID_SERVER_RESPONSE); + } + // Increment by 4 to skip "\r\n\r\n" + pBuff += 4; + + // Adjust buffer data length for header size + transfer_len -= (pBuff - g_buff); + + // If data in chunked format, calculate the chunk size + if(isChunked == 1) + { + retVal = getChunkSize(&transfer_len, &pBuff, &recv_size); + if(retVal < 0) + { + // Error + printf(" Problem with connection to server\r\n"); + return retVal; + } + } + + // Open file to save the downloaded file + retVal = _fs.sl_FsOpen((uint8_t *)FILE_NAME, + FS_MODE_OPEN_WRITE, &Token, &fileHandle); + if(retVal < 0) + { + // File Doesn't exit create a new of 45 KB file + retVal = _fs.sl_FsOpen((uint8_t *)FILE_NAME, + _fs.FS_MODE_OPEN_CREATE(SIZE_45K,_FS_FILE_OPEN_FLAG_COMMIT|_FS_FILE_PUBLIC_WRITE), + &Token, &fileHandle); + if(retVal < 0) + { + printf(" Error during opening the file\r\n"); + return retVal; + } + } + + while (0 < transfer_len) + { + // For chunked data recv_size contains the chunk size to be received + // while the transfer_len contains the data in the buffer + if(recv_size <= transfer_len) + { + // write the recv_size + retVal = _fs.sl_FsWrite(fileHandle, g_BytesReceived, + (uint8_t *)pBuff, recv_size); + if(retVal < recv_size) + { + // Close file without saving + retVal = _fs.sl_FsClose(fileHandle, 0, (unsigned char*)"A", 1); + printf(" Error during writing the file\r\n"); + return FILE_WRITE_ERROR; + } + transfer_len -= recv_size; + g_BytesReceived +=recv_size; + pBuff += recv_size; + recv_size = 0; + + if(isChunked == 1) + { + // if data in chunked format calculate next chunk size + pBuff += 2; // 2 bytes for <CR> <LF> + transfer_len -= 2; + + if(getChunkSize(&transfer_len, &pBuff, &recv_size) < 0) + { + // Error + break; + } + + // if next chunk size is zero we have received the complete file + if(recv_size == 0) + { + eof_detected = 1; + break; + } + + if(recv_size < transfer_len) + { + // Code will enter this section if the new chunk size is less then + // then the transfer size. This will the last chunk of file received + + retVal = _fs.sl_FsWrite(fileHandle, g_BytesReceived, + (uint8_t *)pBuff, recv_size); + if(retVal < recv_size) + { + // Close file without saving + retVal = _fs.sl_FsClose(fileHandle, 0, (unsigned char*)"A", 1); + printf(" Error during writing the file\r\n"); + return FILE_WRITE_ERROR; + } + transfer_len -= recv_size; + g_BytesReceived +=recv_size; + pBuff += recv_size; + recv_size = 0; + + pBuff += 2; // 2bytes for <CR> <LF> + transfer_len -= 2; + + // Calculate the next chunk size, should be zero + if(getChunkSize(&transfer_len, &pBuff, &recv_size) < 0) + { + // Error + break; + } + + // if next chunk size is non zero error + if(recv_size != 0) + { + // Error + break; + } + eof_detected = 1; + break; + } + else + { + // write data on the file + retVal = _fs.sl_FsWrite(fileHandle, g_BytesReceived, + (uint8_t *)pBuff, transfer_len); + if(retVal < transfer_len) + { + // Close file without saving + retVal = _fs.sl_FsClose(fileHandle, 0, (unsigned char*)"A", 1); + printf(" Error during writing the file\r\n"); + ASSERT_ON_ERROR(FILE_WRITE_ERROR); + } + recv_size -= transfer_len; + g_BytesReceived +=transfer_len; + } + } + // complete file received exit + if(recv_size == 0) + { + eof_detected = 1; + break; + } + } + else + { + // write data on the file + retVal = _fs.sl_FsWrite(fileHandle, g_BytesReceived, + (uint8_t *)pBuff, transfer_len); + if (retVal < 0) + { + // Close file without saving + retVal = _fs.sl_FsClose(fileHandle, 0, (unsigned char*)"A", 1); + printf(" Error during writing the file\r\n"); + ASSERT_ON_ERROR(FILE_WRITE_ERROR); + } + g_BytesReceived +=transfer_len; + recv_size -= transfer_len; + } + + memset(g_buff, 0, sizeof(g_buff)); + + transfer_len = _socket.sl_Recv(g_SockID, &g_buff[0], MAX_BUFF_SIZE, 0); + if(transfer_len <= 0) + ASSERT_ON_ERROR(TCP_RECV_ERROR); + + pBuff = g_buff; + } + + // If user file has checksum which can be used to verify the temporary + // file then file should be verified + // In case of invalid file (FILE_NAME) should be closed without saving to + // recover the previous version of file + if(0 > transfer_len || eof_detected == 0) + { + // Close file without saving + retVal = _fs.sl_FsClose(fileHandle, 0, (unsigned char*)"A", 1); + printf(" Error While File Download\r\n"); + ASSERT_ON_ERROR(INVALID_FILE); + } + else + { + // Save and close file + retVal = _fs.sl_FsClose(fileHandle, 0, 0, 0); + ASSERT_ON_ERROR(retVal); + } + + return SUCCESS;; +} +*/ + +/*! + \brief Connecting to a WLAN Access point + + This function connects to the required AP (SSID_NAME). + The function will return once we are connected and have acquired IP address + + \param[in] None + + \return 0 on success, negative error-code on error + + \note + + \warning If the WLAN connection fails or we don't acquire an IP address, + We will be stuck in this function forever. +*/ +int32_t cc3100::establishConnectionWithAP() +{ + + SlSecParams_t secParams = {0}; + int32_t retVal = 0; + + secParams.Key = (signed char *)PASSKEY; + secParams.KeyLen = strlen(PASSKEY); + secParams.Type = SEC_TYPE; + + retVal = _wlan.sl_WlanConnect((signed char *)SSID_NAME, strlen(SSID_NAME), 0, &secParams, 0); + ASSERT_ON_ERROR(retVal); + + /* Wait */ + while((!IS_CONNECTED(g_Status,STATUS_BIT_CONNECTION)) || (!IS_IP_ACQUIRED(g_Status,STATUS_BIT_IP_ACQUIRED))) { _nonos._SlNonOsMainLoopTask(); } + + return SUCCESS; +} + +/*! + \brief This function checks the LAN connection by pinging the AP's gateway + + \param[in] None + + \return 0 on success, negative error-code on error +*/ +int32_t cc3100::checkLanConnection() +{ + SlPingStartCommand_t pingParams = {0}; + SlPingReport_t pingReport = {0}; + + int32_t retVal = -1; + + CLR_STATUS_BIT(g_Status, STATUS_BIT_PING_DONE); + g_PingPacketsRecv = 0; + + /* Set the ping parameters */ + pingParams.PingIntervalTime = PING_INTERVAL; + pingParams.PingSize = PING_PKT_SIZE; + pingParams.PingRequestTimeout = PING_TIMEOUT; + pingParams.TotalNumberOfAttempts = PING_ATTEMPTS; + pingParams.Flags = 0; + pingParams.Ip = g_GatewayIP; + + /* Check for LAN connection */ + retVal = _netapp.sl_NetAppPingStart( (SlPingStartCommand_t*)&pingParams, SL_AF_INET, + (SlPingReport_t*)&pingReport, SimpleLinkPingReport); + ASSERT_ON_ERROR(retVal); + + /* Wait */ + while(!IS_PING_DONE(g_Status,STATUS_BIT_PING_DONE)) { _nonos._SlNonOsMainLoopTask(); } + + if(0 == g_PingPacketsRecv) + { + /* Problem with LAN connection */ + ASSERT_ON_ERROR(LAN_CONNECTION_FAILED); + } + + /* LAN connection is successful */ + return SUCCESS; +} + +/*! + \brief This function checks the internet connection by pinging + the external-host (HOST_NAME) + + \param[in] None + + \return 0 on success, negative error-code on error +*/ +int32_t cc3100::checkInternetConnection() +{ + SlPingStartCommand_t pingParams = {0}; + SlPingReport_t pingReport = {0}; + + uint32_t ipAddr = 0; + + int32_t retVal = -1; + + CLR_STATUS_BIT(g_Status, STATUS_BIT_PING_DONE); + g_PingPacketsRecv = 0; + + /* Set the ping parameters */ + pingParams.PingIntervalTime = PING_INTERVAL; + pingParams.PingSize = PING_PKT_SIZE; + pingParams.PingRequestTimeout = PING_TIMEOUT; + pingParams.TotalNumberOfAttempts = PING_ATTEMPTS; + pingParams.Flags = 0; + pingParams.Ip = g_GatewayIP; + + /* Check for Internet connection */ + retVal = _netapp.sl_NetAppDnsGetHostByName((unsigned char *)HOST_NAME, strlen(HOST_NAME), &ipAddr, SL_AF_INET); + ASSERT_ON_ERROR(retVal); + + /* Replace the ping address to match HOST_NAME's IP address */ + pingParams.Ip = ipAddr; + + /* Try to ping HOST_NAME */ + retVal = _netapp.sl_NetAppPingStart( (SlPingStartCommand_t*)&pingParams, SL_AF_INET, + (SlPingReport_t*)&pingReport, SimpleLinkPingReport); + ASSERT_ON_ERROR(retVal); + + /* Wait */ + while(!IS_PING_DONE(g_Status,STATUS_BIT_PING_DONE)) { _nonos._SlNonOsMainLoopTask(); } + + if (0 == g_PingPacketsRecv) + { + /* Problem with internet connection*/ + ASSERT_ON_ERROR(INTERNET_CONNECTION_FAILED); + } + + /* Internet connection is successful */ + return SUCCESS; +} + +const int8_t StartResponseLUT[8] = +{ + ROLE_UNKNOWN_ERR, + ROLE_STA, + ROLE_STA_ERR, + ROLE_AP, + ROLE_AP_ERR, + ROLE_P2P, + ROLE_P2P_ERR, + ROLE_UNKNOWN_ERR +}; + +/*****************************************************************************/ +/* Internal functions */ +/*****************************************************************************/ + +int16_t cc3100::_sl_GetStartResponseConvert(uint32_t Status) +{ + return (int16_t)StartResponseLUT[Status & 0x7]; + +} + +/*****************************************************************************/ +/* API Functions */ +/*****************************************************************************/ + +bool cc3100::IS_PING_DONE(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_CONNECTED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_STA_CONNECTED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_IP_ACQUIRED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_IP_LEASED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_CONNECTION_FAILED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_P2P_NEG_REQ_RECEIVED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_SMARTCONFIG_DONE(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +bool cc3100::IS_SMARTCONFIG_STOPPED(uint32_t status_variable,const uint32_t bit){ + + g_Status = status_variable; + + if(0 != (g_Status & ((uint32_t)1L<<(bit)))){ + return TRUE; + }else{ + return FALSE; + } +} + +void cc3100::CLR_STATUS_BIT(uint32_t status_variable, const uint32_t bit){ + + g_Status = status_variable; + g_Status &= ~((uint32_t)1L<<(bit)); + +} + +void cc3100::SET_STATUS_BIT(uint32_t status_variable, const uint32_t bit){ + + g_Status = status_variable; + g_Status |= ((uint32_t)1L<<(bit)); + +} + +/*****************************************************************************/ +/* sl_Task */ +/*****************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_Task) +void cc3100::sl_Task(void) +{ +#ifdef _SlTaskEntry + _nonos._SlNonOsMainLoopTask; + +#endif +} +#endif + +/*****************************************************************************/ +/* sl_Start */ +/*****************************************************************************/ +#if _SL_INCLUDE_FUNC(sl_Start) +int16_t cc3100::sl_Start(const void* pIfHdl, int8_t* pDevName, const P_INIT_CALLBACK pInitCallBack) +{ + int16_t ObjIdx = MAX_CONCURRENT_ACTIONS; + InitComplete_t AsyncRsp; + + /* Perform any preprocessing before enable networking services */ + sl_DeviceEnablePreamble();//stub only + + /* ControlBlock init */ + _driver._SlDrvDriverCBInit(); + + /* open the interface: usually SPI or UART */ + if (NULL == pIfHdl) + { + g_pCB->FD = _spi.spi_Open((int8_t *)pDevName, 0); + } + else + { + g_pCB->FD = (_SlFd_t)pIfHdl; + } + + ObjIdx = _driver._SlDrvProtectAsyncRespSetting((uint8_t *)&AsyncRsp, START_STOP_ID, SL_MAX_SOCKETS); + + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + printf("SL_POOL_IS_EMPTY\r\n"); + return SL_POOL_IS_EMPTY; + } + + if( g_pCB->FD >= (_SlFd_t)0) { + _spi.CC3100_disable(); + + g_pCB->pInitCallback = pInitCallBack; + + _spi.CC3100_enable(); + + if (NULL == pInitCallBack) { + + _driver._SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + + /*release Pool Object*/ + _driver._SlDrvReleasePoolObj(g_pCB->FunctionParams.AsyncExt.ActionIndex); + return _sl_GetStartResponseConvert(AsyncRsp.Status); + } + else + { + return SL_RET_CODE_OK; + } + } + + return SL_BAD_INTERFACE; + + +} +#endif + +/*************************************************************************** +_sl_HandleAsync_InitComplete - handles init complete signalling to +a waiting object +****************************************************************************/ +void cc3100::_sl_HandleAsync_InitComplete(void *pVoidBuf) +{ + + InitComplete_t *pMsgArgs = (InitComplete_t *)_SL_RESP_ARGS_START(pVoidBuf); + + _driver._SlDrvProtectionObjLockWaitForever(); + + if(g_pCB->pInitCallback) { + g_pCB->pInitCallback(_sl_GetStartResponseConvert(pMsgArgs->Status)); + } else { + memcpy(g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].pRespArgs, pMsgArgs, sizeof(InitComplete_t)); + _driver._SlDrvSyncObjSignal(&g_pCB->ObjPool[g_pCB->FunctionParams.AsyncExt.ActionIndex].SyncObj); + } + _driver._SlDrvProtectionObjUnLock(); + + if(g_pCB->pInitCallback) { + _driver._SlDrvReleasePoolObj(g_pCB->FunctionParams.AsyncExt.ActionIndex); + } + +} + +/***************************************************************************** +sl_stop +******************************************************************************/ +typedef union { + _DevStopCommand_t Cmd; + _BasicResponse_t Rsp; +} _SlStopMsg_u; + +const _SlCmdCtrl_t _SlStopCmdCtrl = { + SL_OPCODE_DEVICE_STOP_COMMAND, + sizeof(_DevStopCommand_t), + sizeof(_BasicResponse_t) +}; + +#if _SL_INCLUDE_FUNC(sl_Stop) +int16_t cc3100::sl_Stop(const uint16_t timeout) +{ + int16_t RetVal=0; + _SlStopMsg_u Msg; + _BasicResponse_t AsyncRsp; + int8_t ObjIdx = MAX_CONCURRENT_ACTIONS; + /* if timeout is 0 the shutdown is forced immediately */ + if( 0 == timeout ) { + _spi.registerInterruptHandler(NULL, NULL); + _spi.CC3100_disable(); + RetVal = _spi.spi_Close(g_pCB->FD); + + } else { + /* let the device make the shutdown using the defined timeout */ + Msg.Cmd.Timeout = timeout; + + + + + + ObjIdx = _driver._SlDrvProtectAsyncRespSetting((uint8_t *)&AsyncRsp, START_STOP_ID, SL_MAX_SOCKETS); + if (MAX_CONCURRENT_ACTIONS == ObjIdx) + { + return SL_POOL_IS_EMPTY; + } + + VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlStopCmdCtrl, &Msg, NULL)); + + if(SL_OS_RET_CODE_OK == (int16_t)Msg.Rsp.status) + { + _driver._SlDrvSyncObjWaitForever(&g_pCB->ObjPool[ObjIdx].SyncObj); + Msg.Rsp.status = AsyncRsp.status; + RetVal = Msg.Rsp.status; + } + + _driver._SlDrvReleasePoolObj((uint8_t)ObjIdx); + + _spi.registerInterruptHandler(NULL, NULL); + _spi.CC3100_disable(); + _spi.spi_Close(g_pCB->FD); + } + _driver._SlDrvDriverCBDeinit(); + + return RetVal; +} +#endif + + +/***************************************************************************** +sl_EventMaskSet +*****************************************************************************/ +typedef union { + _DevMaskEventSetCommand_t Cmd; + _BasicResponse_t Rsp; +} _SlEventMaskSetMsg_u; + +#if _SL_INCLUDE_FUNC(sl_EventMaskSet) +const _SlCmdCtrl_t _SlEventMaskSetCmdCtrl = { + SL_OPCODE_DEVICE_EVENTMASKSET, + sizeof(_DevMaskEventSetCommand_t), + sizeof(_BasicResponse_t) +}; + +int16_t cc3100::sl_EventMaskSet(uint8_t EventClass , uint32_t Mask) +{ + _SlEventMaskSetMsg_u Msg; + Msg.Cmd.group = EventClass; + Msg.Cmd.mask = Mask; + + VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlEventMaskSetCmdCtrl, &Msg, NULL)); + + return (int16_t)Msg.Rsp.status; +} +#endif + +/****************************************************************************** +sl_EventMaskGet +******************************************************************************/ +typedef union { + _DevMaskEventGetCommand_t Cmd; + _DevMaskEventGetResponse_t Rsp; +} _SlEventMaskGetMsg_u; + +#if _SL_INCLUDE_FUNC(sl_EventMaskGet) +const _SlCmdCtrl_t _SlEventMaskGetCmdCtrl = { + SL_OPCODE_DEVICE_EVENTMASKGET, + sizeof(_DevMaskEventGetCommand_t), + sizeof(_DevMaskEventGetResponse_t) +}; + +int16_t cc3100::sl_EventMaskGet(uint8_t EventClass, uint32_t *pMask) +{ + _SlEventMaskGetMsg_u Msg; + + Msg.Cmd.group = EventClass; + + VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlEventMaskGetCmdCtrl, &Msg, NULL)); + + *pMask = Msg.Rsp.mask; + return SL_RET_CODE_OK; +} +#endif + +/****************************************************************************** +sl_DevGet +******************************************************************************/ + +typedef union { + _DeviceSetGet_t Cmd; + _DeviceSetGet_t Rsp; +} _SlDeviceMsgGet_u; + +#if _SL_INCLUDE_FUNC(sl_DevGet) +const _SlCmdCtrl_t _SlDeviceGetCmdCtrl = { + SL_OPCODE_DEVICE_DEVICEGET, + sizeof(_DeviceSetGet_t), + sizeof(_DeviceSetGet_t) +}; + +int32_t cc3100::sl_DevGet(uint8_t DeviceGetId, uint8_t *pOption,uint8_t *pConfigLen, uint8_t *pValues) +{ + _SlDeviceMsgGet_u Msg; + _SlCmdExt_t CmdExt; + + if (*pConfigLen == 0) { + return SL_EZEROLEN; + } + + if( pOption ) { + _driver._SlDrvResetCmdExt(&CmdExt); + CmdExt.RxPayloadLen = *pConfigLen; + + CmdExt.pRxPayload = (uint8_t *)pValues; + + + Msg.Cmd.DeviceSetId = DeviceGetId; + + Msg.Cmd.Option = (uint16_t)*pOption; + + VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlDeviceGetCmdCtrl, &Msg, &CmdExt)); + + if( pOption ) { + *pOption = (uint8_t)Msg.Rsp.Option; + } + + if (CmdExt.RxPayloadLen < CmdExt.ActualRxPayloadLen) { + *pConfigLen = (uint8_t)CmdExt.RxPayloadLen; + return SL_ESMALLBUF; + } else { + *pConfigLen = (uint8_t)CmdExt.ActualRxPayloadLen; + } + + return (int16_t)Msg.Rsp.Status; + } else { + return -1; + } +} +#endif + +/****************************************************************************** +sl_DevSet +******************************************************************************/ +typedef union { + _DeviceSetGet_t Cmd; + _BasicResponse_t Rsp; +} _SlDeviceMsgSet_u; + +#if _SL_INCLUDE_FUNC(sl_DevSet) +const _SlCmdCtrl_t _SlDeviceSetCmdCtrl = { + SL_OPCODE_DEVICE_DEVICESET, + sizeof(_DeviceSetGet_t), + sizeof(_BasicResponse_t) +}; + +int32_t cc3100::sl_DevSet(const uint8_t DeviceSetId, const uint8_t Option, const uint8_t ConfigLen, const uint8_t *pValues) +{ + _SlDeviceMsgSet_u Msg; + _SlCmdExt_t CmdExt; + + _driver._SlDrvResetCmdExt(&CmdExt); + CmdExt.TxPayloadLen = (ConfigLen+3) & (~3); + + CmdExt.pTxPayload = (uint8_t *)pValues; + + + + Msg.Cmd.DeviceSetId = DeviceSetId; + Msg.Cmd.ConfigLen = ConfigLen; + Msg.Cmd.Option = Option; + + VERIFY_RET_OK(_driver._SlDrvCmdOp((_SlCmdCtrl_t *)&_SlDeviceSetCmdCtrl, &Msg, &CmdExt)); + + return (int16_t)Msg.Rsp.status; +} +#endif + +/****************************************************************************** +sl_UartSetMode +******************************************************************************/ +#ifdef SL_IF_TYPE_UART +typedef union { + _DevUartSetModeCommand_t Cmd; + _DevUartSetModeResponse_t Rsp; +} _SlUartSetModeMsg_u; + +#if _SL_INCLUDE_FUNC(sl_UartSetMode) +const _SlCmdCtrl_t _SlUartSetModeCmdCtrl = { + SL_OPCODE_DEVICE_SETUARTMODECOMMAND, + sizeof(_DevUartSetModeCommand_t), + sizeof(_DevUartSetModeResponse_t) +}; + +int16_t cc3100::sl_UartSetMode(const SlUartIfParams_t* pUartParams) +{ + _SlUartSetModeMsg_u Msg; + uint32_t magicCode = 0xFFFFFFFF; + + Msg.Cmd.BaudRate = pUartParams->BaudRate; + Msg.Cmd.FlowControlEnable = pUartParams->FlowControlEnable; + + + VERIFY_RET_OK(_SlDrvCmdOp((_SlCmdCtrl_t *)&_SlUartSetModeCmdCtrl, &Msg, NULL)); + + /* cmd response OK, we can continue with the handshake */ + if (SL_RET_CODE_OK == Msg.Rsp.status) { + sl_IfMaskIntHdlr(); + + /* Close the comm port */ + sl_IfClose(g_pCB->FD); + + /* Re-open the comm port */ + sl_IfOpen((void * )pUartParams, UART_IF_OPEN_FLAG_RE_OPEN); + sl_IfUnMaskIntHdlr(); + + /* send the magic code and wait for the response */ + sl_IfWrite(g_pCB->FD, (uint8_t* )&magicCode, 4); + + magicCode = UART_SET_MODE_MAGIC_CODE; + sl_IfWrite(g_pCB->FD, (uint8_t* )&magicCode, 4); + + /* clear magic code */ + magicCode = 0; + + /* wait (blocking) till the magic code to be returned from device */ + sl_IfRead(g_pCB->FD, (uint8_t* )&magicCode, 4); + + /* check for the received magic code matching */ + if (UART_SET_MODE_MAGIC_CODE != magicCode) { + _SL_ASSERT(0); + } + } + + return (int16_t)Msg.Rsp.status; +} +#endif +#endif + +}//namespace + +