test
Dependents: mbed-os-example-blinky-1stDevDemo
Diff: SpwfSAInterface.cpp
- Revision:
- 0:79ce2b184a43
diff -r 000000000000 -r 79ce2b184a43 SpwfSAInterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SpwfSAInterface.cpp Wed May 23 14:37:10 2018 +0000 @@ -0,0 +1,512 @@ +/* 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 SpwfSAInterface.cpp + * @author STMicroelectronics + * @brief Implementation of the NetworkStack for the SPWF Device + ****************************************************************************** + * @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 "SpwfSAInterface.h" +#include "mbed_debug.h" +#include "BlockExecuter.h" + +#if MBED_CONF_RTOS_PRESENT +static Mutex _spwf_mutex; // assuming a recursive mutex +static void _spwf_lock() { + (void)(_spwf_mutex.lock()); +} +static Callback<void()> _callback_spwf_lock(&_spwf_lock); + +static void _spwf_unlock() { + (void)(_spwf_mutex.unlock()); +} +static Callback<void()> _callback_spwf_unlock(&_spwf_unlock); + +#define SYNC_HANDLER \ + BlockExecuter sync_handler(_callback_spwf_unlock, _callback_spwf_lock) +#else +#define SYNC_HANDLER +#endif + + +SpwfSAInterface::SpwfSAInterface(PinName tx, PinName rx, + PinName rts, PinName cts, bool debug, + PinName wakeup, PinName reset) +: _spwf(tx, rx, rts, cts, *this, debug, wakeup, reset), + _dbg_on(debug) +{ + inner_constructor(); + reset_credentials(); +} + +nsapi_error_t SpwfSAInterface::init(void) +{ + _spwf.setTimeout(SPWF_INIT_TIMEOUT); + + if(_spwf.startup(0)) { + return NSAPI_ERROR_OK; + } + else return NSAPI_ERROR_DEVICE_ERROR; +} + +nsapi_error_t SpwfSAInterface::connect(void) +{ + int mode; + char *pass_phrase = ap_pass; + SYNC_HANDLER; + + // check for valid SSID + if(ap_ssid[0] == '\0') { + return NSAPI_ERROR_PARAMETER; + } + + switch(ap_sec) + { + case NSAPI_SECURITY_NONE: + mode = 0; + pass_phrase = NULL; + break; + case NSAPI_SECURITY_WEP: + mode = 1; + break; + case NSAPI_SECURITY_WPA: + case NSAPI_SECURITY_WPA2: + mode = 2; + break; + default: + mode = 2; + break; + } + + // First: disconnect + if(_connected_to_network) { + if(!disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + } + + //initialize the device before connecting + if(!_isInitialized) + { + if(init() != NSAPI_ERROR_OK) return NSAPI_ERROR_DEVICE_ERROR; + _isInitialized=true; + } + + // Then: (re-)connect + _spwf.setTimeout(SPWF_CONNECT_TIMEOUT); + + if (!_spwf.connect(ap_ssid, pass_phrase, mode)) { + return NSAPI_ERROR_AUTH_FAILURE; + } + + if (!_spwf.getIPAddress()) { + return NSAPI_ERROR_DHCP_FAILURE; + } + + _connected_to_network = true; + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::connect(const char *ssid, const char *pass, nsapi_security_t security, + uint8_t channel) +{ + nsapi_error_t ret; + SYNC_HANDLER; + + if (channel != 0) { + return NSAPI_ERROR_UNSUPPORTED; + } + + ret = set_credentials(ssid, pass, security); + if(ret != NSAPI_ERROR_OK) return ret; + + return connect(); +} + +nsapi_error_t SpwfSAInterface::disconnect(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_DISCONNECT_TIMEOUT); + + if (!_spwf.disconnect()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + return NSAPI_ERROR_OK; +} + +const char *SpwfSAInterface::get_ip_address(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getIPAddress(); +} + +const char *SpwfSAInterface::get_mac_address(void) +{ + SYNC_HANDLER; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getMACAddress(); +} + +const char *SpwfSAInterface::get_gateway(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return NULL; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getGateway(); +} + +const char *SpwfSAInterface::get_netmask(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return NULL; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getNetmask(); +} + +nsapi_error_t SpwfSAInterface::socket_open(void **handle, nsapi_protocol_t proto) +{ + int internal_id; + SYNC_HANDLER; + + for (internal_id = 0; internal_id < SPWFSA_SOCKET_COUNT; internal_id++) { + if(_ids[internal_id].internal_id == SPWFSA_SOCKET_COUNT) break; + } + + if(internal_id == SPWFSA_SOCKET_COUNT) { + debug_if(_dbg_on, "NO Socket ID Error\r\n"); + return NSAPI_ERROR_NO_SOCKET; + } + + spwf_socket_t *socket = &_ids[internal_id]; + socket->internal_id = internal_id; + socket->spwf_id = SPWFSA_SOCKET_COUNT; + socket->server_gone = false; + socket->no_more_data = false; + socket->proto = proto; + socket->addr = SocketAddress(); + + *handle = socket; + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::socket_connect(void *handle, const SocketAddress &addr) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + MBED_ASSERT(((unsigned int)socket->internal_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + if(_socket_has_connected(socket->internal_id)) { + return NSAPI_ERROR_IS_CONNECTED; + } + + _spwf.setTimeout(SPWF_OPEN_TIMEOUT); + + const char *proto = (socket->proto == NSAPI_UDP) ? "u" : "t"; //"s" for secure socket? + + if(addr.get_ip_version() != NSAPI_IPv4) { // IPv6 not supported (yet) + return NSAPI_ERROR_UNSUPPORTED; + } + + { + BlockExecuter netsock_wa_obj(Callback<void()>(&_spwf, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(&_spwf, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /* block asynchronous indications */ + if(!_spwf._winds_off()) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + { + BlockExecuter bh_handler(Callback<void()>(&_spwf, &SPWFSAxx::_execute_bottom_halves)); + { + BlockExecuter winds_enabler(Callback<void()>(&_spwf, &SPWFSAxx::_winds_on)); + + if(!_spwf.open(proto, &socket->spwf_id, addr.get_ip_address(), addr.get_port())) { + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_DEVICE_ERROR; + } + + /* check for the module to report a valid id */ + MBED_ASSERT(((unsigned int)socket->spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); + + _internal_ids[socket->spwf_id] = socket->internal_id; + socket->addr = addr; + + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_OK; + } + } + } +} + +nsapi_error_t SpwfSAInterface::socket_bind(void *handle, const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_listen(void *handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_accept(nsapi_socket_t server, nsapi_socket_t *handle, SocketAddress *address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t SpwfSAInterface::socket_close(void *handle) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + int internal_id = socket->internal_id; + SYNC_HANDLER; + + if(!_socket_is_open(internal_id)) return NSAPI_ERROR_NO_SOCKET; + + if(_socket_has_connected(socket)) { + _spwf.setTimeout(SPWF_CLOSE_TIMEOUT); + if (!_spwf.close(socket->spwf_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _internal_ids[socket->spwf_id] = SPWFSA_SOCKET_COUNT; + } + + _ids[internal_id].internal_id = SPWFSA_SOCKET_COUNT; + _ids[internal_id].spwf_id = SPWFSA_SOCKET_COUNT; + + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t SpwfSAInterface::socket_send(void *handle, const void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + CHECK_NOT_CONNECTED_ERR(); + + _spwf.setTimeout(SPWF_SEND_TIMEOUT); + return _spwf.send(socket->spwf_id, data, size, socket->internal_id); +} + +nsapi_size_or_error_t SpwfSAInterface::socket_recv(void *handle, void *data, unsigned size) +{ + SYNC_HANDLER; + + return _socket_recv(handle, data, size, false); +} + +nsapi_size_or_error_t SpwfSAInterface::_socket_recv(void *handle, void *data, unsigned size, bool datagram) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + + CHECK_NOT_CONNECTED_ERR(); + + if(!_socket_has_connected(socket)) { + return NSAPI_ERROR_WOULD_BLOCK; + } else if(socket->no_more_data) { + return 0; + } + + _spwf.setTimeout(SPWF_RECV_TIMEOUT); + + int32_t recv = _spwf.recv(socket->spwf_id, (char*)data, (uint32_t)size, datagram); + + MBED_ASSERT(!_spwf._is_event_callback_blocked()); + MBED_ASSERT((recv != 0) || (size == 0)); + + if (recv < 0) { + if(!_socket_is_still_connected(socket)) { + socket->no_more_data = true; + return 0; + } + + return NSAPI_ERROR_WOULD_BLOCK; + } + + return recv; +} + +nsapi_size_or_error_t SpwfSAInterface::socket_sendto(void *handle, const SocketAddress &addr, const void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + CHECK_NOT_CONNECTED_ERR(); + + if ((_socket_has_connected(socket)) && (socket->addr != addr)) { + _spwf.setTimeout(SPWF_CLOSE_TIMEOUT); + if (!_spwf.close(socket->spwf_id)) { + return NSAPI_ERROR_DEVICE_ERROR; + } + _internal_ids[socket->spwf_id] = SPWFSA_SOCKET_COUNT; + socket->spwf_id = SPWFSA_SOCKET_COUNT; + } + + _spwf.setTimeout(SPWF_CONN_SND_TIMEOUT); + if (!_socket_has_connected(socket)) { + nsapi_error_t err = socket_connect(socket, addr); + if (err < 0) { + return err; + } + } + + return socket_send(socket, data, size); +} + +nsapi_size_or_error_t SpwfSAInterface::socket_recvfrom(void *handle, SocketAddress *addr, void *data, unsigned size) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + nsapi_error_t ret; + SYNC_HANDLER; + + ret = _socket_recv(socket, data, size, true); + if (ret >= 0 && addr) { + *addr = socket->addr; + } + + return ret; +} + +void SpwfSAInterface::socket_attach(void *handle, void (*callback)(void *), void *data) +{ + spwf_socket_t *socket = (spwf_socket_t*)handle; + SYNC_HANDLER; + + if(!_socket_is_open(socket)) return; // might happen e.g. after module hard fault or voluntary disconnection + + _cbs[socket->internal_id].callback = callback; + _cbs[socket->internal_id].data = data; +} + +void SpwfSAInterface::event(void) { + for (int internal_id = 0; internal_id < SPWFSA_SOCKET_COUNT; internal_id++) { + if (_cbs[internal_id].callback && (_ids[internal_id].internal_id != SPWFSA_SOCKET_COUNT)) { + _cbs[internal_id].callback(_cbs[internal_id].data); + } + } +} + +nsapi_error_t SpwfSAInterface::set_credentials(const char *ssid, const char *pass, nsapi_security_t security) +{ + SYNC_HANDLER; + + if((ssid == NULL) || (strlen(ssid) == 0)) { + return NSAPI_ERROR_PARAMETER; + } + + if((pass != NULL) && (strlen(pass) > 0)) { + if(strlen(pass) < sizeof(ap_pass)) { + if(security == NSAPI_SECURITY_NONE) { + return NSAPI_ERROR_PARAMETER; + } + } else { + return NSAPI_ERROR_PARAMETER; + } + } else if(security != NSAPI_SECURITY_NONE) { + return NSAPI_ERROR_PARAMETER; + } + + reset_credentials(); + + ap_sec = security; + strncpy(ap_ssid, ssid, sizeof(ap_ssid) - 1); + strncpy(ap_pass, pass, sizeof(ap_pass) - 1); + + return NSAPI_ERROR_OK; +} + +nsapi_error_t SpwfSAInterface::set_channel(uint8_t channel) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +int8_t SpwfSAInterface::get_rssi(void) +{ + SYNC_HANDLER; + + if(!_connected_to_network) return 0; + + _spwf.setTimeout(SPWF_MISC_TIMEOUT); + return _spwf.getRssi(); +} + +nsapi_size_or_error_t SpwfSAInterface::scan(WiFiAccessPoint *res, unsigned count) +{ + SYNC_HANDLER; + + nsapi_size_or_error_t ret; + + //initialize the device before scanning + if(!_isInitialized) + { + if(init() != NSAPI_ERROR_OK) return NSAPI_ERROR_DEVICE_ERROR; + } + + _spwf.setTimeout(SPWF_SCAN_TIMEOUT); + + { + BlockExecuter netsock_wa_obj(Callback<void()>(&_spwf, &SPWFSAxx::_unblock_event_callback), + Callback<void()>(&_spwf, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */ + + /* block asynchronous indications */ + if(!_spwf._winds_off()) { + MBED_ASSERT(_spwf._call_event_callback_blocked == 1); + + return NSAPI_ERROR_DEVICE_ERROR; + } + + ret = _spwf.scan(res, count); + + /* unblock asynchronous indications */ + _spwf._winds_on(); + } + + MBED_ASSERT(!_spwf._is_event_callback_blocked()); + + //de-initialize the device after scanning + if(!_isInitialized) + { + nsapi_error_t err = disconnect(); + if(err != NSAPI_ERROR_OK) return err; + } + + return ret; +}