| /* |
| * 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; |
| } |