blob: 9228948f5cd045370337cd9431122f35d535eb5a [file] [log] [blame]
/*
* FreeRTOS Wi-Fi for LPC54018 IoT Module V1.0.1
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file iot_wifi.c
* @brief Wi-Fi Interface.
*/
#include <stdio.h>
#include "FreeRTOS.h"
#include "iot_wifi.h"
#include "wifi_common.h"
#include "qcom_api.h"
#include "atheros_wifi.h"
/* This is here because the maximum DNS name length is defined in iot_secure_sockets.h.
* Wi-Fi must not have a dependency on iot_secure_sockets.h
*/
#define wifiMAX_DNS_NAME_LENGTH 253
/* Only 1 Wi-Fi module is present at the time */
static uint8_t g_devid = 0;
/* NOTE: Could be located on stack */
static QCOM_SSID g_ssid = { 0 };
/* NOTE: Could be located on stack */
static QCOM_PASSPHRASE g_passphr = { 0 };
/* Semaphore for connection */
static SemaphoreHandle_t g_connect_semaph;
/* Semaphore for dhcp response */
static SemaphoreHandle_t g_dhcp_semaph;
/* Protect API */
static SemaphoreHandle_t g_wifi_semaph;
/* Wi-Fi/HW hardware configuration */
QCA_CONTEXT_STRUCT g_wifi_ctx = { 0 };
/* Wi-Fi status - turned on */
static uint8_t g_wifi_is_on = 0;
/* Wi-Fi status - turned on */
static uint8_t g_connected = 0;
/* What event is expected */
enum expected_event {
expected_event_default,
expected_event_connect,
expected_event_disconnect,
};
enum expected_event g_expected_event = expected_event_default;
/* Wi-Fi security */
static WIFISecurity_t g_security = eWiFiSecurityNotSupported;
extern const QCA_MAC_IF_STRUCT ATHEROS_WIFI_IF;
/* Wi-Fi interface object */
const QCA_IF_STRUCT g_wifi_if = {
.MAC_IF = &ATHEROS_WIFI_IF,
.MAC_NUMBER = 0,
.PHY_NUMBER = 0,
.PHY_ADDRESS = 0,
};
/* Wi-Fi params */
const QCA_PARAM_STRUCT g_wifi_params = {
.QCA_IF = &g_wifi_if,
.MODE = Auto_Negotiate,
.OPTIONS = 0,
.NUM_RX_PCBS = WLAN_CONFIG_NUM_PRE_ALLOC_RX_BUFFERS,
};
/* Singleton, provides Wi-Fi context structure */
QCA_CONTEXT_STRUCT * wlan_get_context(void)
{
return &g_wifi_ctx;
}
static void ip_to_pxIPAddr(uint32_t ip, uint8_t *pxIPAddr)
{
pxIPAddr[0] = (uint8_t)(ip >> 24);
pxIPAddr[1] = (uint8_t)(ip >> 16);
pxIPAddr[2] = (uint8_t)(ip >> 8);
pxIPAddr[3] = (uint8_t)(ip);
}
static void pxIPAddr_to_ip(uint8_t *pxIPAddr, uint32_t *ip32)
{
*ip32 = (((pxIPAddr[0]) & 0xFF) << 24) | \
(((pxIPAddr[1]) & 0xFF) << 16) | \
(((pxIPAddr[2]) & 0xFF) << 8) | \
(((pxIPAddr[3]) & 0xFF));
}
static BaseType_t post_semaph(SemaphoreHandle_t semaph)
{
BaseType_t result = pdFALSE;
result = xSemaphoreGive(semaph);
// assert(pdPASS == result);
return result;
}
/* Invoked from 'driver_task', on SUCCESS post semaphore */
static void aws_connect_cb(QCOM_ONCONNECT_EVENT event, uint8_t devid, QCOM_BSSID bssid, boolean bss_conn)
{
if ((g_security == eWiFiSecurityWPA) || (g_security == eWiFiSecurityWPA2))
{
/* 4 -way handshake completed */
if (0x10 == (int)event)
{
g_connected = 1;
post_semaph(g_connect_semaph);
}
/* invalid profile, auth failed */
else if (0xa == (int)event)
{
g_connected = 0;
post_semaph(g_connect_semaph);
}
else if (QCOM_ONCONNECT_EVENT_SUCCESS == event)
{
/* Do nothing, wait for 4-way handshake */
}
else if (QCOM_ONCONNECT_EVENT_DISCONNECT == event)
{
g_connected = 0;
/* Avoid situation when receive disconnect followed by connect */
if (expected_event_disconnect == g_expected_event)
{
post_semaph(g_connect_semaph);
}
}
else {
assert(0);
}
}
else
{
if (QCOM_ONCONNECT_EVENT_SUCCESS == event)
{
g_connected = 1;
post_semaph(g_connect_semaph);
}
else if (QCOM_ONCONNECT_EVENT_DISCONNECT == event)
{
g_connected = 0;
/* Avoid situation when receive disconnect followed by connect */
if (expected_event_disconnect == g_expected_event)
{
post_semaph(g_connect_semaph);
}
}
else
{
assert(0);
}
}
}
/* Current IP settings */
static uint32_t g_ip4_addr = 0;
static uint32_t g_ip4_mask = 0;
static uint32_t g_ip4_gw = 0;
static inline uint32_t IPs_are_valid(uint32_t ip4_addr, uint32_t ip4_mask, uint32_t ip4_gw)
{
uint32_t bitval = 0, expected_bitval = 1;
/* not valid */
if (0 == ip4_mask)
return 0;
/* Check continuous 1 and 0 in BE format */
for (int8_t i = 31; i >= 0; i--)
{
bitval = (ip4_mask >> i) & 1;
if (0 == expected_bitval && 1 == bitval)
{
/* not valid */
return 0;
}
expected_bitval = bitval;
}
/* Not valid ip against gw */
return (ip4_addr != 0 && ((ip4_addr & ip4_mask) == (ip4_gw & ip4_mask)));
}
/* Receive DHCP response */
static uint32_t aws_dhcpc_callback(uint32_t ip, uint32_t mask, uint32_t gw)
{
BaseType_t result = pdFALSE;
(void)result;
/* Unify to BE format */
g_ip4_addr = A_CPU2BE32(ip);
g_ip4_mask = A_CPU2BE32(mask);
g_ip4_gw = A_CPU2BE32(gw);
result = xSemaphoreGive(g_dhcp_semaph);
// assert(pdPASS == result);
return 0;
}
static WIFIReturnCode_t conv_security_to_qcom(WIFISecurity_t api_sec, WLAN_AUTH_MODE *qcom_auth, WLAN_CRYPT_TYPE *qcom_crypt)
{
switch (api_sec)
{
case eWiFiSecurityOpen:
*qcom_crypt = WLAN_CRYPT_NONE;
*qcom_auth = WLAN_AUTH_NONE;
break;
case eWiFiSecurityWEP:
*qcom_crypt = WLAN_CRYPT_WEP_CRYPT;
*qcom_auth = WLAN_AUTH_WEP;
break;
case eWiFiSecurityWPA:
// *qcom_crypt = WLAN_CRYPT_TKIP_CRYPT;
*qcom_crypt = WLAN_CRYPT_AES_CRYPT;
*qcom_auth = WLAN_AUTH_WPA_PSK;
break;
case eWiFiSecurityWPA2:
// *qcom_crypt = WLAN_CRYPT_TKIP_CRYPT;
*qcom_crypt = WLAN_CRYPT_AES_CRYPT;
*qcom_auth = WLAN_AUTH_WPA2_PSK;
break;
default:
return eWiFiFailure;
}
return eWiFiSuccess;
}
static WIFIReturnCode_t conv_qcom_to_mode(QCOM_WLAN_DEV_MODE dev_mode, WIFIDeviceMode_t *pxDeviceMode)
{
switch (dev_mode)
{
case QCOM_WLAN_DEV_MODE_STATION:
*pxDeviceMode = eWiFiModeStation;
break;
case QCOM_WLAN_DEV_MODE_AP:
*pxDeviceMode = eWiFiModeAP;
break;
case QCOM_WLAN_DEV_MODE_ADHOC:
*pxDeviceMode = eWiFiModeP2P;
break;
default:
return eWiFiFailure;
}
return eWiFiSuccess;
}
static WIFIReturnCode_t conv_mode_to_qcom(WIFIDeviceMode_t xDeviceMode, QCOM_WLAN_DEV_MODE *dev_mode)
{
switch (xDeviceMode)
{
case eWiFiModeStation:
*dev_mode = QCOM_WLAN_DEV_MODE_STATION;
break;
case eWiFiModeAP:
*dev_mode = QCOM_WLAN_DEV_MODE_AP;
break;
case eWiFiModeP2P:
*dev_mode = QCOM_WLAN_DEV_MODE_ADHOC;
break;
default:
return eWiFiFailure;
}
return eWiFiSuccess;
}
/**
* @brief Initializes the Wi-Fi module.
*
* This function must be called exactly once before any other
* Wi-Fi functions (including socket functions) can be used.
*
* @return eWiFiSuccess if everything succeeds, eWiFiFailure otherwise.
*/
WIFIReturnCode_t WIFI_On( void )
{
A_STATUS result;
/* Prevent re-initialization. WiFi is aleady on this is successful. */
if (g_wifi_is_on)
return eWiFiSuccess;
/* Initialize Wi-Fi shield */
result = (A_STATUS)WIFISHIELD_Init();
if (A_OK != result)
return eWiFiFailure;
/* Power off the WLAN and wait 30ms */
CUSTOM_HW_POWER_UP_DOWN(NULL, false);
vTaskDelay(MSEC_TO_TICK(30));
g_wifi_ctx.PARAM_PTR = &g_wifi_params;
if (A_OK != ATHEROS_WIFI_IF.INIT(&g_wifi_ctx))
return eWiFiFailure;
/* Disable low power mode to avoid SPI bus flood */
qcom_power_set_mode(0, MAX_PERF_POWER, USER);
/* Create a on_connect semaphore, */
g_wifi_semaph = xSemaphoreCreateBinary();
if (NULL == g_wifi_semaph)
return eWiFiFailure;
xSemaphoreGive(g_wifi_semaph);
/* Create a on_connect semaphore, */
g_connect_semaph = xSemaphoreCreateBinary();
if (NULL == g_connect_semaph)
return eWiFiFailure;
/* Create a dhcp semaphore, */
g_dhcp_semaph = xSemaphoreCreateBinary();
if (NULL == g_dhcp_semaph)
return eWiFiFailure;
/* Wait for Wi-Fi */
vTaskDelay(MSEC_TO_TICK(100));
g_wifi_is_on = 1;
return eWiFiSuccess;
}
WIFIReturnCode_t WIFI_Off( void )
{
return eWiFiNotSupported;
}
/**
* @brief Connects to Access Point.
*
* @param[in] pxNetworkParams Configuration to join AP.
*
* @return eWiFiSuccess if connection is successful, eWiFiFailure otherwise.
*/
WIFIReturnCode_t WIFI_ConnectAP( const WIFINetworkParams_t * const pxNetworkParams )
{
WLAN_AUTH_MODE auth_mode;
WLAN_CRYPT_TYPE crypt_type;
WIFIReturnCode_t status = eWiFiFailure;
const TickType_t connect_timeout = pdMS_TO_TICKS( 30000UL );
const TickType_t dhcp_timeout = pdMS_TO_TICKS( 20000UL );
(void)dhcp_timeout;
uint32_t tmp_ip4_addr = 0, tmp_ip4_mask = 0, tmp_ip4_gw = 0;
uint8_t ucDhcpSuccessful = 0;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if (NULL == pxNetworkParams || NULL == pxNetworkParams->pcSSID || NULL == pxNetworkParams->pcPassword)
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
/* Reset "connect" and "dhcp" semaphores */
g_expected_event = expected_event_default;
xQueueReset((void*)g_connect_semaph);
xQueueReset((void*)g_dhcp_semaph);
/* Disconnect Wi-Fi */
if (g_connected)
{
g_expected_event = expected_event_disconnect;
if (A_OK == qcom_disconnect(g_devid))
{
/* Consider disconnected */
g_connected = 0;
/* Wait for callback, that is invoked from 'driver_task' context */
if (pdTRUE != xSemaphoreTake(g_connect_semaph, connect_timeout))
{
break;
}
/* Workaround for ARP cache */
if (0 != g_ip4_gw)
{
if (A_OK != qcom_ipconfig(g_devid, QCOM_IPCONFIG_STATIC, &g_ip4_gw, &g_ip4_mask, &g_ip4_gw))
{
break;
}
g_ip4_addr = g_ip4_mask = g_ip4_gw = 0;
}
}
else
{
break;
}
}
/* Set Wi-Fi to device mode */
if (A_OK != (A_STATUS)qcom_op_set_mode(g_devid, QCOM_WLAN_DEV_MODE_STATION))
{
break;
}
/* Set SSID, must be done before auth, cipher and passphrase */
strncpy(g_ssid.ssid, pxNetworkParams->pcSSID, sizeof(g_ssid.ssid) - 1);
if (A_OK != (A_STATUS)qcom_set_ssid(g_devid, &g_ssid))
{
break;
}
g_security = pxNetworkParams->xSecurity;
/* Convert 'WIFISecurity_t' to 'WLAN_AUTH_MODE', 'WLAN_CRYPT_TYPE' */
if (eWiFiSuccess != conv_security_to_qcom(pxNetworkParams->xSecurity, &auth_mode, &crypt_type))
{
break;
}
/* Set encyption mode */
if (A_OK != (A_STATUS)qcom_sec_set_encrypt_mode(g_devid, crypt_type))
{
break;
}
/* Set auth mode */
if (A_OK != qcom_sec_set_auth_mode(g_devid, auth_mode))
{
break;
}
/* Set passphrase */
strncpy(g_passphr.passphrase, pxNetworkParams->pcPassword, sizeof(g_passphr.passphrase) - 1);
if (A_OK != qcom_sec_set_passphrase(g_devid, &g_passphr))
{
break;
}
/* Set channel */
if (0 != pxNetworkParams->cChannel)
{
if (A_OK != qcom_set_channel(g_devid, pxNetworkParams->cChannel))
{
break;
}
}
/* Set connect_callback */
if (A_OK != qcom_set_connect_callback(g_devid, (void *)aws_connect_cb))
{
break;
}
g_expected_event = expected_event_connect;
/* Commit settings to Wi-Fi module. Calling this function starts the connection process. */
if (A_OK != qcom_commit(g_devid))
{
break;
}
/* Wait for callback, that is invoked from 'driver_task' context. This callback sets g_connected to connected (1) or disconnected (0). */
if (pdTRUE != xSemaphoreTake(g_connect_semaph, connect_timeout))
{
break;
}
/* Register DHCP callback */
if (A_OK != qcom_dhcpc_register_cb(0, (void*)aws_dhcpc_callback))
{
break;
}
/* Try several attempts in worst case */
for (int i = 0; i < 10 && 0 == g_ip4_addr; i++)
{
/* Perform DHCP request */
if (A_OK != qcom_ipconfig(g_devid, QCOM_IPCONFIG_DHCP, &tmp_ip4_addr, &tmp_ip4_mask, &tmp_ip4_gw))
{
/* Error case, terminate loops */
break;
}
/* DHCP response is available immediately */
if (IPs_are_valid(tmp_ip4_addr, tmp_ip4_mask, tmp_ip4_gw))
{
/* Valid IP of DHCP response */
g_ip4_addr = tmp_ip4_addr;
g_ip4_mask = tmp_ip4_mask;
g_ip4_gw = tmp_ip4_gw;
/* Expected case, terminate loops */
break;
}
#if defined(WIFISHIELD_IS_GT202) && (WIFISHIELD_IS == WIFISHIELD_IS_GT202)
/* If DHCP response is not available immediately, wait for DHCP callback */
if (pdTRUE == xSemaphoreTake(g_dhcp_semaph, dhcp_timeout))
{
/* If semaphore is posted before deadline, expects valid IPs assigned in callback */
/* Expected case, terminate loops */
break;
}
#endif
#if defined(WIFISHIELD_IS_SILEX2401) && (WIFISHIELD_IS == WIFISHIELD_IS_SILEX2401)
/* If there is no callback response or callback does not catch the deadline, try IPCONFIG_QUERY */
if (A_OK != qcom_ipconfig(g_devid, QCOM_IPCONFIG_QUERY, &tmp_ip4_addr, &tmp_ip4_mask, &tmp_ip4_gw))
{
/* Error case, terminate loops */
break;
}
/* Check received IPCONFIG response */
if (IPs_are_valid(tmp_ip4_addr, tmp_ip4_mask, tmp_ip4_gw))
{
/* Valid IP of DHCP response */
g_ip4_addr = tmp_ip4_addr;
g_ip4_mask = tmp_ip4_mask;
g_ip4_gw = tmp_ip4_gw;
/* Expected case, terminate loops */
break;
}
#endif
}
/* Still not a valid IP, report error */
if (!IPs_are_valid(g_ip4_addr, g_ip4_mask, g_ip4_gw))
{
break;
}
/* Otherwise after all is said and done the DHCP request is successful. */
else
{
ucDhcpSuccessful = 1;
}
/* Everything is OK. We connected to the AP and got an IP address with DHCP. */
status = ( g_connected && ucDhcpSuccessful ) ? eWiFiSuccess : eWiFiFailure;
} while (0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
/**
* @brief Disconnects from Access Point.
*
* @param[in] None.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_Disconnect( void )
{
const TickType_t connect_timeout = pdMS_TO_TICKS( 20000UL );
WIFIReturnCode_t status = eWiFiFailure;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
/* Reset connect semaphore */
g_expected_event = expected_event_default;
xQueueReset((void*)g_connect_semaph);
/* Connected to AP */
if (g_connected)
{
/* Register connect cb */
if (A_OK != qcom_set_connect_callback(g_devid, (void *)aws_connect_cb))
{
break;
}
g_expected_event = expected_event_disconnect;
/* Make disconnect request */
if (A_OK != qcom_disconnect(g_devid))
{
break;
}
// /* Consider disconnected, even if it's not yet confirmed by callback */
// g_connected = 0;
/* Wait for disconnect response */
if (pdTRUE != xSemaphoreTake(g_connect_semaph, connect_timeout))
{
break;
}
/* Workaround for ARP cache */
if (0 != g_ip4_gw)
{
if (A_OK != qcom_ipconfig(g_devid, QCOM_IPCONFIG_STATIC, &g_ip4_gw, &g_ip4_mask, &g_ip4_gw))
break;
g_ip4_addr = g_ip4_mask = g_ip4_gw = 0;
}
/* Consider OK */
status = eWiFiSuccess;
}
/* Disconnected from AP */
else
{
status = eWiFiSuccess;
}
} while(0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
/**
* @brief Resets the Wi-Fi Module.
*
* @param[in] None.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_Reset( void )
{
return eWiFiNotSupported;
}
/**
* @brief Sets Wi-Fi mode.
*
* @param[in] xDeviceMode - Mode of the device Station / Access Point /P2P.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_SetMode( WIFIDeviceMode_t xDeviceMode )
{
QCOM_WLAN_DEV_MODE dev_mode = QCOM_WLAN_DEV_MODE_INVALID;
WIFIReturnCode_t status = eWiFiFailure;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
if (eWiFiSuccess != conv_mode_to_qcom(xDeviceMode, &dev_mode))
break;
if (A_OK != (A_STATUS)qcom_op_set_mode(g_devid, dev_mode))
break;
status = eWiFiSuccess;
} while (0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;;
}
/**
* @brief Gets Wi-Fi mode.
*
* @param[in] pxDeviceMode - return mode Station / Access Point /P2P
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_GetMode( WIFIDeviceMode_t * pxDeviceMode )
{
QCOM_WLAN_DEV_MODE dev_mode = QCOM_WLAN_DEV_MODE_INVALID;
WIFIReturnCode_t status = eWiFiFailure;
/* Check params */
if (NULL == pxDeviceMode)
return eWiFiFailure;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
if (A_OK != (A_STATUS)qcom_op_get_mode(g_devid, &dev_mode))
break;
if (eWiFiSuccess != conv_qcom_to_mode(dev_mode, pxDeviceMode))
break;
status = eWiFiSuccess;
} while(0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
/**
* @brief Wi-Fi Add Network profile.
*
* Adds Wi-Fi network to network list in non-volatile memory
*
* @param[in] pxNetworkProfile - network profile parameters
* @param[out] pusIndex - network profile index
*
* @return Profile stored index on success, or negative error code on failure..
*
* @see WIFINetworkParams_t
*/
WIFIReturnCode_t WIFI_NetworkAdd(const WIFINetworkProfile_t * const pxNetworkProfile, uint16_t * pusIndex )
{
return eWiFiNotSupported;
}
/**
* @brief Wi-Fi Get Network profile .
*
* Gets Wi-Fi network params at given index from network list in non-volatile memory
*
* @param[out] pxNetworkProfile - pointer to return network profile parameters
* @param[in] usIndex - Index of the network profile, must be between 0 to wificonfigMAX_NETWORK_PROFILES
* @return eWiFiSuccess if success, eWiFiFailure otherwise.
*
* @see WIFINetworkParams_t
*/
WIFIReturnCode_t WIFI_NetworkGet( WIFINetworkProfile_t * pxNetworkProfile,
uint16_t uxIndex )
{
return eWiFiNotSupported;
}
/**
* @brief Wi-Fi Delete Network profile .
*
* Deletes Wi-Fi network from network list at given index in non-volatile memory
*
* @param[in] usIndex - Index of the network profile, must be between 0 to wificonfigMAX_NETWORK_PROFILES
* wificonfigMAX_NETWORK_PROFILES as index will delete all network profiles
*
* @return eWiFiSuccess if deleted, eWiFiFailure otherwise.
*
*/
WIFIReturnCode_t WIFI_NetworkDelete( uint16_t uxIndex )
{
return eWiFiNotSupported;
}
/**
* @brief Ping an IP address in the network.
*
* @param[in] IP Address to ping.
* @param[in] Number of times to ping
* @param[in] Interval in mili seconds for ping operation
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_Ping( uint8_t * pxIPAddr,
uint16_t xCount,
uint32_t xIntervalMS )
{
uint32_t failed_cnt = 0;
uint32_t ip4_addr = 0;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if ((NULL == pxIPAddr) || (0 == xCount))
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
pxIPAddr_to_ip(pxIPAddr, &ip4_addr);
for (uint16_t i = 0; i < xCount; i++)
{
if (xIntervalMS == 0)
xIntervalMS = 20000; // max 20 seconds
if (A_OK != qcom_ping_ms(ip4_addr, 32, xIntervalMS))
{
failed_cnt++;
}
}
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
/* Report failure if all attempts failed */
return failed_cnt == xCount ? eWiFiFailure : eWiFiSuccess;
}
/**
* @brief Retrieves the Wi-Fi interface's IP address.
*
* @param[in] IP Address buffer.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_GetIP( uint8_t * pxIPAddr )
{
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if (NULL == pxIPAddr)
return eWiFiFailure;
ip_to_pxIPAddr(g_ip4_addr, pxIPAddr);
return g_ip4_addr == 0 ? eWiFiFailure : eWiFiSuccess;
}
/**
* @brief Retrieves the Wi-Fi interface's MAC address.
*
* @param[in] MAC Address buffer.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_GetMAC( uint8_t * pxMac )
{
WIFIReturnCode_t status = eWiFiFailure;
uint8_t mac_addr[ATH_MAC_LEN] = {0};
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if (NULL == pxMac)
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
if (A_OK != qcom_get_bssid(g_devid, mac_addr))
break;
memcpy(pxMac, mac_addr, ATH_MAC_LEN);
status = eWiFiSuccess;
} while (0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
/**
* @brief Retrieves host IP address from URL using DNS
*
* @param[in] pxHost - Host URL.
* @param[in] pxIPAddr - IP Address buffer.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_GetHostIP( char * pxHost,
uint8_t * pxIPAddr )
{
WIFIReturnCode_t status = eWiFiFailure;
uint32_t result = A_OK;
IP_ADDR_T tmp_ip = {0};
IP_ADDR_T dns_ip = {0};
uint32_t dns_servers[MAX_DNSADDRS] = {0};
uint32_t dns_servers_num = 0;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if ((NULL == pxIPAddr) || (NULL == pxHost))
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
/* 'pxHost' is an IP address */
int tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0;
if (4 == sscanf(pxHost, "%u.%u.%u.%u", &tmp1, &tmp2, &tmp3, &tmp4))
{
pxIPAddr[0] = tmp4;
pxIPAddr[1] = tmp3;
pxIPAddr[2] = tmp2;
pxIPAddr[3] = tmp1;
status = eWiFiSuccess;
break;
}
/* Obtain DNS IP from DHCP result */
result = qcom_dns_server_address_get(dns_servers, &dns_servers_num);
if ((A_OK != result) || (dns_servers_num == 0))
break;
/* Perform DNS/UDP request, loop over DNS servers until first success */
for (uint32_t dns_idx = 0; dns_idx < dns_servers_num; dns_idx++)
{
dns_ip.s_addr = dns_servers[dns_idx];
if (A_OK != qcom_dns_resolver(dns_ip, pxHost, &tmp_ip, wificonfigDNS_QUERY_TIMEOUT))
continue;
/* Copy to output format and terminate loop*/
pxIPAddr[0] = (uint8_t)(tmp_ip.s_addr >> 24);
pxIPAddr[1] = (uint8_t)(tmp_ip.s_addr >> 16);
pxIPAddr[2] = (uint8_t)(tmp_ip.s_addr >> 8);
pxIPAddr[3] = (uint8_t)(tmp_ip.s_addr);
status = eWiFiSuccess;
break;
}
} while(0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
/**
* @brief Retrieves IP address in Access Point mode
*
* @param[in] pxIPAddr - IP Address buffer.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_GetAccessPointIP( uint8_t * pxIPAddr )
{
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if (NULL == pxIPAddr)
return eWiFiFailure;
ip_to_pxIPAddr(g_ip4_addr, pxIPAddr);
return g_ip4_addr == 0 ? eWiFiFailure : eWiFiSuccess;
}
/**
* @brief Perform WiF Scan
*
* @param[in] pxBuffer - Buffer for scan results.
* @param[in] uxNumNetworks - Number of networks in scan result.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_Scan( WIFIScanResult_t * pxBuffer,
uint8_t uxNumNetworks )
{
WIFIReturnCode_t status = eWiFiFailure;
QCOM_BSS_SCAN_INFO *scan_result = NULL;
int16_t scan_result_num = 0;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if ((NULL == pxBuffer) || (0 == uxNumNetworks))
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
/* Note: won't work if SSID is set already */
if (A_OK != qcom_set_scan(g_devid, NULL))
break;
if (qcom_get_scan(g_devid, &scan_result, &scan_result_num))
break;
/* Get MIN(scan_result_num, uxNumNetworks) */
if (scan_result_num > (int16_t)uxNumNetworks)
scan_result_num = (int16_t)uxNumNetworks;
for (int16_t i = 0 ; i < scan_result_num; i++)
{
strncpy((char*)pxBuffer->cSSID, (char const*)scan_result[i].ssid, wificonfigMAX_SSID_LEN);
strncpy((char*)pxBuffer->ucBSSID, (char const*)scan_result[i].bssid, wificonfigMAX_BSSID_LEN);
pxBuffer->cRSSI = scan_result[i].rssi;
pxBuffer->cChannel = scan_result[i].channel;
pxBuffer->ucHidden = 0;
if (!scan_result[i].security_enabled)
{
pxBuffer->xSecurity = eWiFiSecurityOpen;
}
else if (
(0 == scan_result[i].rsn_cipher) ||
(ATH_CIPHER_TYPE_WEP & scan_result[i].rsn_cipher)
)
{
pxBuffer->xSecurity = eWiFiSecurityWEP;
}
else if (ATH_CIPHER_TYPE_CCMP & scan_result[i].rsn_cipher)
{
pxBuffer->xSecurity = eWiFiSecurityWPA2;
}
else
{
/* TODO: Expect WPA */
pxBuffer->xSecurity = eWiFiSecurityWPA;
}
#if 0
PRINTF("-----------------------\r\n");
PRINTF("channel: %d \r\n", scan_result[i].channel);
PRINTF("ssid_len: %d \r\n", scan_result[i].ssid_len);
PRINTF("rssi: %d \r\n", scan_result[i].rssi);
PRINTF("security_enabled: %d \r\n", scan_result[i].security_enabled);
PRINTF("beacon_period: %d \r\n", scan_result[i].beacon_period);
PRINTF("preamble: %d \r\n", scan_result[i].preamble);
PRINTF("bss_type: %d \r\n", scan_result[i].bss_type);
PRINTF("bssid: %x%x%x%x%x%x \r\n",
scan_result[i].bssid[0],
scan_result[i].bssid[1],
scan_result[i].bssid[2],
scan_result[i].bssid[3],
scan_result[i].bssid[4],
scan_result[i].bssid[5]
);
PRINTF("ssid: %s \r\n", scan_result[i].ssid);
PRINTF("rsn_cipher: %d \r\n", scan_result[i].rsn_cipher);
PRINTF("rsn_auth: %d \r\n", scan_result[i].rsn_auth);
PRINTF("wpa_cipher: %d \r\n", scan_result[i].wpa_cipher);
PRINTF("wpa_auth: %d \r\n", scan_result[i].wpa_auth);
#endif
pxBuffer += 1;
}
status = eWiFiSuccess;
} while (0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
/**
* @brief Configure SoftAP
*
* @param[in] pxNetworkParams - Network params to configure AP.
*
* @return eWiFiSuccess if everything succeeds, failure code otherwise.
*/
WIFIReturnCode_t WIFI_ConfigureAP(const WIFINetworkParams_t * const pxNetworkParams )
{
WIFIReturnCode_t status = eWiFiFailure;
WLAN_AUTH_MODE auth_mode = WLAN_AUTH_INVALID;
WLAN_CRYPT_TYPE crypt_type = WLAN_CRYPT_INVALID;
/* Check initialization */
if (!g_wifi_is_on)
return eWiFiFailure;
/* Check params */
if (NULL == pxNetworkParams || NULL == pxNetworkParams->pcSSID || NULL == pxNetworkParams->pcPassword)
return eWiFiFailure;
/* Acquire semaphore */
if (xSemaphoreTake(g_wifi_semaph, portMAX_DELAY) == pdTRUE)
{
do {
/* Set Wi-Fi to device mode */
if (A_OK != (A_STATUS)qcom_op_set_mode(g_devid, QCOM_WLAN_DEV_MODE_AP))
break;
/* Set SSID, must be done before auth, cipher and passphrase */
strncpy(g_ssid.ssid, pxNetworkParams->pcSSID, sizeof(g_ssid.ssid) - 1);
if (A_OK != (A_STATUS)qcom_set_ssid(g_devid, &g_ssid))
break;
/* Convert 'WIFISecurity_t' to 'WLAN_AUTH_MODE', 'WLAN_CRYPT_TYPE' */
if (eWiFiSuccess != conv_security_to_qcom(pxNetworkParams->xSecurity, &auth_mode, &crypt_type))
break;
/* Set encyption mode */
if (A_OK != (A_STATUS)qcom_sec_set_encrypt_mode(g_devid, crypt_type))
break;
/* Set auth mode */
if (A_OK != qcom_sec_set_auth_mode(g_devid, auth_mode))
break;
/* Set passphrase */
strncpy(g_passphr.passphrase, pxNetworkParams->pcPassword, sizeof(g_passphr.passphrase) - 1);
if (A_OK != qcom_sec_set_passphrase(g_devid, &g_passphr))
break;
/* Commit settings to WiFi module */
if (A_OK != qcom_commit(g_devid))
break;
status = eWiFiSuccess;
} while (0);
/* Release semaphore */
xSemaphoreGive(g_wifi_semaph);
}
return status;
}
WIFIReturnCode_t WIFI_SetPMMode( WIFIPMMode_t xPMModeType,
const void * pvOptionValue )
{
return eWiFiNotSupported;
}
WIFIReturnCode_t WIFI_GetPMMode( WIFIPMMode_t * pxPMModeType,
void * pvOptionValue )
{
return eWiFiNotSupported;
}
BaseType_t WIFI_IsConnected( void )
{
// uint32_t ip4_addr = 0, ip4_mask = 0, ip4_gw = 0;
BaseType_t xIsConnected = pdFALSE;
// if (A_OK == qcom_ipconfig( g_devid, QCOM_IPCONFIG_DHCP, &ip4_addr, &ip4_mask, &ip4_gw ) )
if (1 == g_connected)
{
xIsConnected = pdTRUE;
}
return xIsConnected;
}
WIFIReturnCode_t WIFI_RegisterNetworkStateChangeEventCallback( IotNetworkStateChangeEventCallback_t xCallback )
{
/** Needs to implement dispatching network state change events **/
return eWiFiNotSupported;
}