Extending the X_NUCLEO_IDW01M1 to allow configuration of the board as an access point
Dependents: X_NUCLEO_IDW01M1_AP_Test
Fork of X_NUCLEO_IDW01M1 by
Spwf_API/SpwfSADevice.cpp
- Committer:
- scsims
- Date:
- 2016-06-21
- Revision:
- 18:b265b3b696f1
- Parent:
- 12:3799f8475c8a
- Child:
- 19:9ab60b80872e
File content as of revision 18:b265b3b696f1:
/* mbed Microcontroller Library * Copyright (c) 20015 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** ****************************************************************************** * @file SpwfSADevice.cpp * @author STMicroelectronics * @brief Implementation of SpwfSADevice class for Wi-Fi mbed ****************************************************************************** * @copy * * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. * * <h2><center>© COPYRIGHT 2016 STMicroelectronics</center></h2> ****************************************************************************** */ #include "SpwfSADevice.h" #include "wifi_module.h" #ifdef __cplusplus extern "C" { #endif void Rx_irq_handler(void); void Wifi_scheduler(void); void Wifi_ticker(void); #ifdef __cplusplus } #endif extern void setSpwfSADevice(SpwfSADevice * dev); #define FORMAT_HEX_STRING "0x%08x" #define HEX_STRING_LENGTH 11 /** * @brief SpwfSADevice constructor * @param tx: Pin USART TX * rx: Pin USART RX * rst: reset pin for Spwf module * wkup: reset pin for Spwf module * rts: Pin USART RTS * @retval none */ SpwfSADevice::SpwfSADevice(PinName tx, PinName rx, PinName rst, PinName wkup, PinName rts): uart_(tx,rx), term_(SERIAL_TX, SERIAL_RX), wakeup_(wkup, PIN_INPUT, PullNone, 0), rst_(rst, PIN_INPUT, PullNone, 1), rts_(rts, PIN_INPUT, PullUp, 0) { setSpwfSADevice(this); sync_wait_signal = false; wait_for_incoming_client = false; wait_for_socket_data = false; } /** * @brief SpwfSADevice destructor * @param none * @retval none */ SpwfSADevice::~SpwfSADevice(void) { //de-constructor } /** * @brief init function initializes timers, gpios, uart * @param none * @retval error value */ int SpwfSADevice::init(void) { printf("SpwfSADevice::init()\n"); WiFi_Status_t status = WiFi_MODULE_SUCCESS; Timer timer; timer.start(); rst_.output(); wakeup_.output(); rts_.output(); term_.baud(9600); term_.format(8, SerialBase::None, 1); uart_.baud(115200); uart_.format(8, SerialBase::None, 1); uart_.set_flow_control(SerialBase::RTS, PA_12, NC);//RTSCTS uart_.attach(Rx_irq_handler, SerialBase::RxIrq); config.power=wifi_active; config.power_level=max; config.dhcp=on;//use DHCP IP address config.ip_addr = "192.168.0.50"; config.netmask_addr = "255.255.255.0"; config.gateway_addr = "192.168.0.1"; config.dns_addr = "192.168.0.1"; /*Initialize the tickers*/ wifi_isr.attach_us(Wifi_ticker, 1000); //decreasing the time period to 1ms may be causing overrun issue with UART?\ //UART error not evident but characters are sometimes missing in pipeline(ring_buffer)\ //specifically in the +WIND:25:WiFi Association with 'STM' successful WIND (why specifically this?) wifi_callback.attach_us(Wifi_scheduler, 5000);//How low can we go? sync_wait_signal = false; status = wifi_init(&config); if(status!=WiFi_MODULE_SUCCESS) { return -1; } while(!sync_wait_signal) { if (timer.read_ms() > _timeout) { return -1; } __NOP(); } return 0; } /** * @brief network connect wrapper function for FW * @param ssid: Access Point (AP) Name String * sec_key: Password String for AP * priv_mode: type of security supported (FW mode) * @retval NSAPI Error Type */ int SpwfSADevice::connect(char * ssid, char * sec_key, WiFi_Priv_Mode priv_mode) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; Timer timer; timer.start(); sync_wait_signal = false; status = wifi_connect(ssid, sec_key, priv_mode); if(status!=WiFi_MODULE_SUCCESS) { return -1; } while(!sync_wait_signal) { if (timer.read_ms() > _timeout) { return -1; } __NOP(); } return 0; } /** * @brief start the mini access point * @param ssid: start with this SSID * @param sec_key: passphrase for STAtions to connect with * @param priv_mode: type of security to set up with * @param channel_num: WiFi channel to use * @param data_rates: bitmap of operational data rates to support * @retval NSAPI Error Type */ int SpwfSADevice::start_access_point(char * ssid, char * sec_key, WiFi_Priv_Mode priv_mode, int channel_num, unsigned int data_rates) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; Timer timer; timer.start(); // Reset the data rate values uint32_t modeNEnabled = 1; char oprMask[] = "0x003fffcf"; if (0x3fffcf != data_rates) { // All data rates must be enabled to allow wireless N (high throughput/HT) mode modeNEnabled = 0; sprintf(oprMask, (const char*)FORMAT_HEX_STRING, data_rates); // Different basic rate mask char basMask[HEX_STRING_LENGTH]; sprintf(basMask, FORMAT_HEX_STRING, data_rates & 0xf); status = SET_Configuration_Addr(WIFI_BAS_RATE_MASK, basMask); if(status != WiFi_MODULE_SUCCESS) return -1; } status = SET_Configuration_Value(WIFI_HT_MODE, modeNEnabled); if(status != WiFi_MODULE_SUCCESS) return -1; status = SET_Configuration_Addr(WIFI_OPR_RATE_MASK, oprMask); if(status != WiFi_MODULE_SUCCESS) return -1; // Start the access point sync_wait_signal = false; status = wifi_ap_start((uint8_t*)ssid, (uint8_t)channel_num); if(status!=WiFi_MODULE_SUCCESS) { return -1; } while(!sync_wait_signal) { if (timer.read_ms() > _timeout) { return -1; } __NOP(); } return 0; } /** * @brief network disconnect wrapper function for FW * @param none * @retval error value */ int SpwfSADevice::disconnect() { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_disconnect();//will set to Idle Mode if(status!=WiFi_MODULE_SUCCESS) { return -1; } return 0; } /** * @brief Get the local IP address * wrapper function for FW * @param none * @retval Null-terminated representation of the local IP address * or null if not yet connected */ const char *SpwfSADevice::getIPAddress() { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = WiFi_Get_IP_Address((uint8_t *)_ip_buffer); if(status!=WiFi_MODULE_SUCCESS) { return NULL; } else return _ip_buffer; } /** * @brief Get the MAC address * wrapper function for FW * @param none * @retval Null-terminated representation of the MAC address * or null if not yet connected */ const char *SpwfSADevice::getMACAddress() { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = WiFi_Get_MAC_Address((uint8_t *)_mac_buffer); if(status!=WiFi_MODULE_SUCCESS) { return NULL; } else return _mac_buffer; } /** * @brief connect to a remote socket * @param hostname: address of socket port_number: port number to connect protocol: TCP/UDP protocol * sock_id: pointer to socket ID returned by FW * @retval error value */ int SpwfSADevice::socket_client_open(uint8_t * hostname, uint32_t port_number, uint8_t * protocol, uint8_t * sock_id) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; //Timeout of synchronous functions? status = wifi_socket_client_open(hostname, port_number, protocol, sock_id); if(status!=WiFi_MODULE_SUCCESS) { *sock_id = 99;//make sure socket id is not set(set to out of bounds of SPWFSA_SOCKET_COUNT range) return -1; } return 0; } /** * @brief write to a remote socket * @param sock_id: FW ID of the socket DataLength: size of the data pData: pointer to data * @retval error value */ int SpwfSADevice::socket_client_write(uint8_t sock_id, uint16_t DataLength,char * pData) { int status=0;//number of bytes status = wifi_socket_client_write(sock_id, DataLength, pData); //map error to enum ns_error_t if(status > 0) { return status; } return 0; } /** * @brief receive from a remote socket * @param sock_id: FW ID of the socket DataLength: size of the data pData: pointer to data * @retval error value */ int SpwfSADevice::socket_client_recv(uint8_t sock_id, uint16_t RecvLength,char * pData) { static Timer recv_timer; //char debug_str[10]; static bool recv_call = true; if(recv_call) { //debug_print("\r\nrecv_call\r\n"); //__disable_irq(); wait_for_socket_data = false; recv_buff = (uint8_t*)pData; //__enable_irq(); if(_timeout>0) recv_timer.start(); recv_call = false; bytes_to_read = RecvLength; bytes_read=0; } if(wait_for_socket_data || recv_timer.read_ms() >= _timeout) { recv_call = true; _timeout = 0; wait_for_socket_data = true; recv_timer.stop(); recv_timer.reset(); wait_ms(1); if(bytes_read == 0) //<bytes_to_read?? return -1;//return error if no bytes are read! else return bytes_read;//return amount of data arrived so far } wait_ms(1); //CHECK:TODO: Need to wait to allow other IRQ's to run in case of non-blocking call? return -1; } /** * @brief scan the network * @param scan_result: scan result data pointer max_scan_number: size of the scan result * @retval error value */ void SpwfSADevice::network_scan(wifi_scan *scan_result, uint16_t max_scan_number) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_network_scan(scan_result, max_scan_number); if(status!=WiFi_MODULE_SUCCESS) { return; } } /** * @brief HTTP GET from remote host * @param hostname: address of remote host path: path to resource port_number: port number * @retval none */ void SpwfSADevice::http_get(uint8_t * hostname, uint8_t * path, uint32_t port_number) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_http_get((uint8_t *)hostname, (uint8_t *)path, port_number); if(status!=WiFi_MODULE_SUCCESS) { return; } } /** * @brief HTTP GET from remote host * @param url_path: complete url of remote resource * @retval none */ void SpwfSADevice::http_post(uint8_t * url_path) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_http_post(url_path); if(status!=WiFi_MODULE_SUCCESS) { return; } } /** * @brief FW callback with data in socket * @param sock_id: FW ID of the socket data_ptr: pointer to data from FW message_size: total data to arrive chunk_size: size of the data in this callback (<= message_size) * @retval none */ void SpwfSADevice::signal_data_receive(uint8_t socket_id, uint8_t * data_ptr, uint32_t message_size, uint32_t chunk_size) { char debug_str[50]; //Data will be copied or returned to user only if there is a pending request //Copy data to pData //sprintf((char*)debug_str,"sock_id: %d, size: %d, chunk: %d\r\n",socket_id, message_size, chunk_size); //debug_print(debug_str); if(recv_buff && !wait_for_socket_data) { if((bytes_read + chunk_size)<= bytes_to_read) { memcpy(recv_buff + bytes_read, data_ptr, chunk_size);//only copy bytes_to_read asked by user//rest of the data is lost!! bytes_read += chunk_size; } else { uint32_t x_size = (bytes_read + chunk_size) - bytes_to_read; memcpy(recv_buff + bytes_read, data_ptr, chunk_size-x_size); bytes_read += (chunk_size-x_size); } if(bytes_read >= bytes_to_read) { __disable_irq(); wait_for_socket_data = true; __enable_irq(); } } else { debug_print("\r\n Socket:: Data Dropped: "); sprintf((char*)debug_str,"%d\r\n",chunk_size); debug_print(debug_str); __disable_irq(); wait_for_socket_data = true; __enable_irq(); } } /** * @brief synchronization function called from FW (used for connect,disconnect, ready, etc.) * @param code: Status code value returned * @retval none */ void SpwfSADevice::signal_synch_wait(WiFi_Status_t code) { if(code == WiFi_DISASSOCIATION) { //do nothing } else { __disable_irq(); sync_wait_signal = true; __enable_irq(); } } /** * @brief close a client socket * @param sock_close_id: FW ID of the socket to close * @retval error value */ int SpwfSADevice::socket_client_close(uint8_t sock_close_id) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_socket_client_close(sock_close_id); //map error to enum ns_error_t if(status!=WiFi_MODULE_SUCCESS) { return -1; } return 0; } /** * @brief open a server socket * @param port_number: port number to listen on * protocol: TCP/UDP protocol * @retval error value */ int SpwfSADevice::socket_server_open(uint32_t port_number, uint8_t * protocol) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_socket_server_open(port_number, protocol); //map error to enum ns_error_t if(status!=WiFi_MODULE_SUCCESS) { return -1; } return 0; } /** * @brief write to a server socket * @param data_length: size of the data * pdata: pointer to data * @retval error value */ int SpwfSADevice::socket_server_write(uint16_t data_length,char * pdata) { int status = 0;//number of bytes status = wifi_socket_server_write(data_length, pdata); //map error to enum ns_error_t if(status > 0) { return status; } return 0; } /** * @brief close a server socket * @param none (only one server socket supported) * @retval error value */ int SpwfSADevice::socket_server_close(void) { WiFi_Status_t status = WiFi_MODULE_SUCCESS; status = wifi_socket_server_close(); //map error to enum ns_error_t if(status!=WiFi_MODULE_SUCCESS) { return -1; } return 0; } /** * @brief attach/remove IRQ handler to UART * @param attach: attach/remove boolean * @retval none */ void SpwfSADevice::spwf_attach_irq(wifi_bool attach) { if(attach) { uart_.attach(Rx_irq_handler, SerialBase::RxIrq); } else { uart_.attach(NULL, SerialBase::RxIrq); } } /** * @brief write byte(s) to the UART * @param cmd: pointer to data * size: size of data * @retval error value */ int SpwfSADevice::spwf_send(const char * cmd, uint16_t size) { Timer timer; int i, bytes; //timer.start(); //uart_.puts(cmd);//string may contain '\0' character in between hence not used for(i=0;i<size;i++) { uart_.putc(cmd[i]); //if (timer.read_ms() > _timeout) { //return -1; //} } bytes = (int) size - 2;//we send 2 bytes extra for module return bytes; } /** * @brief read a byte from the UART * @param none * @retval byte character */ char SpwfSADevice::spwf_get(void) { return(uart_.getc()); } /** * @brief (re)set the SPWF wakeup GPIO pin * @param wake (re)set value * @retval none */ void SpwfSADevice::spwf_wakeup(int wake) { wakeup_.write(wake); } /** * @brief (re)set the SPWF reset GPIO pin * @param reset (re)set value * @retval none */ void SpwfSADevice::spwf_reset(int reset) { rst_.write(reset); } /** * @brief (re)set the SPWF RTS GPIO line * @param rts (re)set value * @retval none */ void SpwfSADevice::spwf_rts(int rts) { rts_.write(rts); } /** * @brief read the SPWF RTS GPIO pin * @param none * @retval none */ int SpwfSADevice::spwf_read_rts() { return(rts_.read()); } /** * @brief send debug print to serial terminal * @param string: data for debug print * @retval none */ void SpwfSADevice::debug_print(const char * string) { term_.puts(string); } /** * @brief (re)set the switch for incoming client (server socket) * @param set: boolean to (re)set * @retval none */ void SpwfSADevice::set_wait_for_incoming_client(bool set) { wait_for_incoming_client = set; } /** * @brief get the switch for incoming client (server socket) * @param none * @retval boolean */ bool SpwfSADevice::get_wait_for_incoming_client() { return wait_for_incoming_client; }