![](/media/cache/profiles/5f55d0baa59f4bc1dc393149183f1492.jpg.50x50_q85.jpg)
wifi test
Dependencies: X_NUCLEO_IKS01A2 mbed-http
Diff: easy-connect/wifi-ism43362/ISM43362/ISM43362.cpp
- Revision:
- 0:24d3eb812fd4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/easy-connect/wifi-ism43362/ISM43362/ISM43362.cpp Wed Sep 05 14:28:24 2018 +0000 @@ -0,0 +1,699 @@ +/* ISM43362 Example +* +* Copyright (c) STMicroelectronics 2018 + * + * 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. + */ +#include <string.h> +#include "ISM43362.h" +#include "mbed_debug.h" + +// activate / de-activate debug +#define ism_debug 0 + +ISM43362::ISM43362(PinName mosi, PinName miso, PinName sclk, PinName nss, PinName resetpin, PinName datareadypin, PinName wakeup, bool debug) + : _bufferspi(mosi, miso, sclk, nss, datareadypin), + _parser(_bufferspi), + _resetpin(resetpin), + _packets(0), _packets_end(&_packets) +{ + DigitalOut wakeup_pin(wakeup); + _bufferspi.format(16, 0); /* 16bits, ploarity low, phase 1Edge, master mode */ + _bufferspi.frequency(20000000); /* up to 20 MHz */ + _active_id = 0xFF; + _FwVersionId = 0; + + _ism_debug = debug || ism_debug; + reset(); +} + +/** + * @brief Parses and returns number from string. + * @param ptr: pointer to string + * @param cnt: pointer to the number of parsed digit + * @retval integer value. + */ +#define CHARISHEXNUM(x) (((x) >= '0' && (x) <= '9') || \ + ((x) >= 'a' && (x) <= 'f') || \ + ((x) >= 'A' && (x) <= 'F')) +#define CHARISNUM(x) ((x) >= '0' && (x) <= '9') +#define CHAR2NUM(x) ((x) - '0') + + +extern "C" int32_t ParseNumber(char *ptr, uint8_t *cnt) +{ + uint8_t minus = 0, i = 0; + int32_t sum = 0; + + if (*ptr == '-') { /* Check for minus character */ + minus = 1; + ptr++; + i++; + } + if (*ptr == 'C') { /* input string from get_firmware_version is Cx.x.x.x */ + ptr++; + } + + while (CHARISNUM(*ptr) || (*ptr == '.')) { /* Parse number */ + if (*ptr == '.') { + ptr++; // next char + } else { + sum = 10 * sum + CHAR2NUM(*ptr); + ptr++; + i++; + } + } + + if (cnt != NULL) { /* Save number of characters used for number */ + *cnt = i; + } + if (minus) { /* Minus detected */ + return 0 - sum; + } + return sum; /* Return number */ +} + +uint32_t ISM43362::get_firmware_version(void) +{ + char tmp_buffer[250]; + char *ptr, *ptr2; + char _fw_version[16]; + + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("I?") && _parser.recv("%[^\n^\r]\r\n", tmp_buffer) && check_response())) { + debug_if(_ism_debug, "ISM43362: get_firmware_version is FAIL\r\n"); + return 0; + } + debug_if(_ism_debug, "ISM43362: get_firmware_version = %s\r\n", tmp_buffer); + + // Get the first version in the string + ptr = strtok((char *)tmp_buffer, ","); + ptr = strtok(NULL, ","); + ptr2 = strtok(NULL, ","); + if (ptr == NULL) { + debug_if(_ism_debug, "ISM43362: get_firmware_version decoding is FAIL\r\n"); + return 0; + } + strncpy(_fw_version, ptr, ptr2 - ptr); + _FwVersionId = ParseNumber(_fw_version, NULL); + + return _FwVersionId; +} + +bool ISM43362::reset(void) +{ + char tmp_buffer[100]; + debug_if(_ism_debug, "ISM43362: Reset Module\r\n"); + _resetpin = 0; + wait_ms(10); + _resetpin = 1; + wait_ms(500); + + /* Wait for prompt line : the string is "> ". */ + /* As the space char is not detected by sscanf function in parser.recv, */ + /* we need to use %[\n] */ + if (!_parser.recv(">%[^\n]", tmp_buffer)) { + debug_if(_ism_debug, "ISM43362: Reset Module failed\r\n"); + return false; + } + return true; +} + +void ISM43362::print_rx_buff(void) +{ + char tmp[150] = {0}; + uint16_t i = 0; + debug_if(_ism_debug, "ISM43362: "); + while (i < 150) { + int c = _parser.getc(); + if (c < 0) { + break; + } + tmp[i] = c; + debug_if(_ism_debug, "0x%2X ", c); + i++; + } + debug_if(_ism_debug, "\n"); + debug_if(_ism_debug, "ISM43362: Buffer content =====%s=====\r\n", tmp); +} + +/* checks the standard OK response of the WIFI module, shouldbe: + * \r\nDATA\r\nOK\r\n>sp + * or + * \r\nERROR\r\nUSAGE\r\n>sp + * function returns true if OK, false otherwise. In case of error, + * print error content then flush buffer */ +bool ISM43362::check_response(void) +{ + char tmp_buffer[100]; + if (!_parser.recv("OK\r\n")) { + print_rx_buff(); + _parser.flush(); + return false; + } + + /* Then we should get the prompt: "> " */ + /* As the space char is not detected by sscanf function in parser.recv, */ + /* we need to use %[\n] */ + if (!_parser.recv(">%[^\n]", tmp_buffer)) { + debug_if(_ism_debug, "ISM43362: Missing prompt in WIFI resp\r\n"); + print_rx_buff(); + _parser.flush(); + return false; + } + + /* Inventek module do stuffing / padding of data with 0x15, + * in case buffer contains such */ + while (1) { + int c = _parser.getc(); + if (c == 0x15) { + // debug_if(_ism_debug, "ISM43362: Flush char 0x%x\n", c); + continue; + } else { + /* How to put it back if needed ? */ + break; + } + } + return true; +} + +bool ISM43362::dhcp(bool enabled) +{ + return (_parser.send("C4=%d", enabled ? 1 : 0) && check_response()); +} + +int ISM43362::connect(const char *ap, const char *passPhrase, ism_security_t ap_sec) +{ + char tmp[256]; + + if (!(_parser.send("C1=%s", ap) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + if (!(_parser.send("C2=%s", passPhrase) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + /* Check security level is acceptable */ + if (ap_sec > ISM_SECURITY_WPA_WPA2) { + debug_if(_ism_debug, "ISM43362: Unsupported security level %d\n", ap_sec); + return NSAPI_ERROR_UNSUPPORTED; + } + + if (!(_parser.send("C3=%d", ap_sec) && check_response())) { + return NSAPI_ERROR_PARAMETER; + } + + if (_parser.send("C0")) { + while (_parser.recv("%[^\n]\n", tmp)) { + if (strstr(tmp, "OK")) { + _parser.flush(); + return NSAPI_ERROR_OK; + } + if (strstr(tmp, "JOIN")) { + if (strstr(tmp, "Failed")) { + _parser.flush(); + return NSAPI_ERROR_AUTH_FAILURE; + } + } + } + } + + return NSAPI_ERROR_NO_CONNECTION; +} + +bool ISM43362::disconnect(void) +{ + return (_parser.send("CD") && check_response()); +} + +const char *ISM43362::getIPAddress(void) +{ + char tmp_ip_buffer[250]; + char *ptr, *ptr2; + + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("C?") + && _parser.recv("%[^\n^\r]\r\n", tmp_ip_buffer) + && check_response())) { + debug_if(_ism_debug, "ISM43362: getIPAddress LINE KO: %s\n", tmp_ip_buffer); + return 0; + } + + /* Get the IP address in the result */ + /* TODO : check if the begining of the string is always = "eS-WiFi_AP_C47F51011231," */ + ptr = strtok((char *)tmp_ip_buffer, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr = strtok(NULL, ","); + ptr2 = strtok(NULL, ","); + if (ptr == NULL) { + return 0; + } + strncpy(_ip_buffer, ptr, ptr2 - ptr); + + tmp_ip_buffer[59] = 0; + debug_if(_ism_debug, "ISM43362: receivedIPAddress: %s\n", _ip_buffer); + + return _ip_buffer; +} + +const char *ISM43362::getMACAddress(void) +{ + if (!(_parser.send("Z5") && _parser.recv("%s\r\n", _mac_buffer) && check_response())) { + debug_if(_ism_debug, "ISM43362: receivedMacAddress LINE KO: %s\n", _mac_buffer); + return 0; + } + + debug_if(_ism_debug, "ISM43362: receivedMacAddress:%s, size=%d\r\n", _mac_buffer, sizeof(_mac_buffer)); + + return _mac_buffer; +} + +const char *ISM43362::getGateway() +{ + char tmp[250]; + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) { + debug_if(_ism_debug, "ISM43362: getGateway LINE KO: %s\r\n", tmp); + return 0; + } + + /* Extract the Gateway in the received buffer */ + char *ptr; + ptr = strtok(tmp, ","); + for (int i = 0; i < 7; i++) { + if (ptr == NULL) { + break; + } + ptr = strtok(NULL, ","); + } + + strncpy(_gateway_buffer, ptr, sizeof(_gateway_buffer)); + + debug_if(_ism_debug, "ISM43362: getGateway: %s\r\n", _gateway_buffer); + + return _gateway_buffer; +} + +const char *ISM43362::getNetmask() +{ + char tmp[250]; + /* Use %[^\n] instead of %s to allow having spaces in the string */ + if (!(_parser.send("C?") && _parser.recv("%[^\n^\r]\r\n", tmp) && check_response())) { + debug_if(_ism_debug, "ISM43362: getNetmask LINE KO: %s\n", tmp); + return 0; + } + + /* Extract Netmask in the received buffer */ + char *ptr; + ptr = strtok(tmp, ","); + for (int i = 0; i < 6; i++) { + if (ptr == NULL) { + break; + } + ptr = strtok(NULL, ","); + } + + strncpy(_netmask_buffer, ptr, sizeof(_netmask_buffer)); + + debug_if(_ism_debug, "ISM43362: getNetmask: %s\r\n", _netmask_buffer); + + return _netmask_buffer; +} + +int8_t ISM43362::getRSSI() +{ + int8_t rssi; + char tmp[25]; + + if (!(_parser.send("CR") && _parser.recv("%s\r\n", tmp) && check_response())) { + debug_if(_ism_debug, "ISM43362: getRSSI LINE KO: %s\r\n", tmp); + return 0; + } + + rssi = ParseNumber(tmp, NULL); + + debug_if(_ism_debug, "ISM43362: getRSSI: %d\r\n", rssi); + + return rssi; +} +/** + * @brief Parses Security type. + * @param ptr: pointer to string + * @retval Encryption type. + */ +extern "C" nsapi_security_t ParseSecurity(char *ptr) +{ + if (strstr(ptr, "Open")) { + return NSAPI_SECURITY_NONE; + } else if (strstr(ptr, "WEP")) { + return NSAPI_SECURITY_WEP; + } else if (strstr(ptr, "WPA2 AES")) { + return NSAPI_SECURITY_WPA2; + } else if (strstr(ptr, "WPA WPA2")) { + return NSAPI_SECURITY_WPA_WPA2; + } else if (strstr(ptr, "WPA2 TKIP")) { + return NSAPI_SECURITY_UNKNOWN; // no match in mbed + } else if (strstr(ptr, "WPA2")) { + return NSAPI_SECURITY_WPA2; // catch any other WPA2 formula + } else if (strstr(ptr, "WPA")) { + return NSAPI_SECURITY_WPA; + } else { + return NSAPI_SECURITY_UNKNOWN; + } +} + +/** + * @brief Convert char in Hex format to integer. + * @param a: character to convert + * @retval integer value. + */ +extern "C" uint8_t Hex2Num(char a) +{ + if (a >= '0' && a <= '9') { /* Char is num */ + return a - '0'; + } else if (a >= 'a' && a <= 'f') { /* Char is lowercase character A - Z (hex) */ + return (a - 'a') + 10; + } else if (a >= 'A' && a <= 'F') { /* Char is uppercase character A - Z (hex) */ + return (a - 'A') + 10; + } + + return 0; +} + +/** + * @brief Extract a hex number from a string. + * @param ptr: pointer to string + * @param cnt: pointer to the number of parsed digit + * @retval Hex value. + */ +extern "C" uint32_t ParseHexNumber(char *ptr, uint8_t *cnt) +{ + uint32_t sum = 0; + uint8_t i = 0; + + while (CHARISHEXNUM(*ptr)) { /* Parse number */ + sum <<= 4; + sum += Hex2Num(*ptr); + ptr++; + i++; + } + + if (cnt != NULL) { /* Save number of characters used for number */ + *cnt = i; + } + return sum; /* Return number */ +} + +bool ISM43362::isConnected(void) +{ + return getIPAddress() != 0; +} + +int ISM43362::scan(WiFiAccessPoint *res, unsigned limit) +{ + unsigned cnt = 0, num = 0; + char *ptr; + char tmp[256]; + + if (!(_parser.send("F0"))) { + debug_if(_ism_debug, "ISM43362: scan error\r\n"); + return 0; + } + + /* Parse the received buffer and fill AP buffer */ + /* Use %[^\n] instead of %s to allow having spaces in the string */ + while (_parser.recv("#%[^\n]\n", tmp)) { + if (limit != 0 && cnt >= limit) { + /* reached end */ + break; + } + nsapi_wifi_ap_t ap = {0}; + debug_if(_ism_debug, "ISM43362: received:%s\n", tmp); + ptr = strtok(tmp, ","); + num = 0; + while (ptr != NULL) { + switch (num++) { + case 0: /* Ignore index */ + case 4: /* Ignore Max Rate */ + case 5: /* Ignore Network Type */ + case 7: /* Ignore Radio Band */ + break; + case 1: + ptr[strlen(ptr) - 1] = 0; + strncpy((char *)ap.ssid, ptr + 1, 32); + break; + case 2: + for (int i = 0; i < 6; i++) { + ap.bssid[i] = ParseHexNumber(ptr + (i * 3), NULL); + } + break; + case 3: + ap.rssi = ParseNumber(ptr, NULL); + break; + case 6: + ap.security = ParseSecurity(ptr); + break; + case 8: + ap.channel = ParseNumber(ptr, NULL); + num = 1; + break; + default: + break; + } + ptr = strtok(NULL, ","); + } + if (res != NULL) { + res[cnt] = WiFiAccessPoint(ap); + } + cnt++; + } + + /* We may stop before having read all the APs list, so flush the rest of + * it as well as OK commands */ + _parser.flush(); + + debug_if(_ism_debug, "ISM43362: End of Scan: cnt=%d\n", cnt); + + return cnt; + +} + +bool ISM43362::open(const char *type, int id, const char *addr, int port) +{ + /* TODO : This is the implementation for the client socket, need to check if need to create openserver too */ + //IDs only 0-3 + if ((id < 0) || (id > 3)) { + debug_if(_ism_debug, "ISM43362: open: wrong id\n"); + return false; + } + /* Set communication socket */ + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P0 issue\n"); + return false; + } + /* Set protocol */ + if (!(_parser.send("P1=%s", type) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P1 issue\n"); + return false; + } + /* Set address */ + if (!(_parser.send("P3=%s", addr) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P3 issue\n"); + return false; + } + if (!(_parser.send("P4=%d", port) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P4 issue\n"); + return false; + } + /* Start client */ + if (!(_parser.send("P6=1") && check_response())) { + debug_if(_ism_debug, "ISM43362: open: P6 issue\n"); + return false; + } + + /* request as much data as possible - i.e. module max size */ + if (!(_parser.send("R1=%d", ES_WIFI_MAX_RX_PACKET_SIZE) && check_response())) { + debug_if(_ism_debug, "ISM43362: open: R1 issue\n"); + return -1; + } + + /* Non blocking mode : set Read Transport Timeout to 1ms */ + if (!(_parser.send("R2=1") && check_response())) { + debug_if(_ism_debug, "ISM43362: open: R2 issue\n"); + return -1; + } + + debug_if(_ism_debug, "ISM43362: open ok with id %d type %s addr %s port %d\n", id, type, addr, port); + + return true; +} + +bool ISM43362::dns_lookup(const char *name, char *ip) +{ + char tmp[30]; + + if (!(_parser.send("D0=%s", name) && _parser.recv("%s\r\n", tmp) + && check_response())) { + debug_if(_ism_debug, "ISM43362 dns_lookup: D0 issue: %s\n", tmp); + return 0; + } + + strncpy(ip, tmp, sizeof(tmp)); + + debug_if(_ism_debug, "ISM43362 dns_lookup: %s ok\n", ip); + return 1; +} + +bool ISM43362::send(int id, const void *data, uint32_t amount) +{ + // The Size limit has to be checked on caller side. + if (amount > ES_WIFI_MAX_TX_PACKET_SIZE) { + debug_if(_ism_debug, "ISM43362 send: max issue\n"); + return false; + } + + /* Activate the socket id in the wifi module */ + if ((id < 0) || (id > 3)) { + return false; + } + if (_active_id != id) { + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + debug_if(_ism_debug, "ISM43362 send: P0 issue\n"); + return false; + } + } + + /* set Write Transport Packet Size */ + int i = _parser.printf("S3=%d\r", (int)amount); + if (i < 0) { + debug_if(_ism_debug, "ISM43362 send: S3 issue\n"); + return false; + } + i = _parser.write((const char *)data, amount, i); + if (i < 0) { + return false; + } + + if (!check_response()) { + return false; + } + + debug_if(_ism_debug, "ISM43362 send: id %d amount %d\n", id, amount); + return true; +} + +int ISM43362::check_recv_status(int id, void *data) +{ + int read_amount; + + debug_if(_ism_debug, "ISM43362 check_recv_status: id %d\r\n", id); + + /* Activate the socket id in the wifi module */ + if ((id < 0) || (id > 3)) { + debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR with id %d\r\n", id); + return -1; + } + + if (_active_id != id) { + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + return -1; + } + } + + + if (!_parser.send("R0")) { + return -1; + } + read_amount = _parser.read((char *)data); + + if (read_amount < 0) { + debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR in data RECV, timeout?\r\n"); + return -1; /* nothing to read */ + } + + /* If there are spurious 0x15 at the end of the data, this is an error + * we hall can get rid off of them :-( + * This should not happen, but let's try to clean-up anyway + */ + char *cleanup = (char *) data; + while ((read_amount > 0) && (cleanup[read_amount - 1] == 0x15)) { + // debug_if(_ism_debug, "ISM43362 check_recv_status: spurious 0X15 trashed\r\n"); + /* Remove the trailling char then search again */ + read_amount--; + } + + if ((read_amount >= 6) && (strncmp("OK\r\n> ", (char *)data, 6) == 0)) { + // debug_if(_ism_debug, "ISM43362 check_recv_status: recv 2 nothing to read=%d\r\n", read_amount); + // read_amount -= 6; + return 0; /* nothing to read */ + } else if ((read_amount >= 8) && (strncmp((char *)((uint32_t) data + read_amount - 8), "\r\nOK\r\n> ", 8)) == 0) { + /* bypass ""\r\nOK\r\n> " if present at the end of the chain */ + read_amount -= 8; + } else { + debug_if(_ism_debug, "ISM43362 check_recv_status: ERROR, flushing %d bytes: ", read_amount); + // for (int i = 0; i < read_amount; i++) { + // debug_if(_ism_debug, "%2X ", cleanup[i]); + // } + // debug_if(_ism_debug, "\r\n (ASCII)", cleanup); + cleanup[read_amount] = 0; + debug_if(_ism_debug, "%s\r\n", cleanup); + return -1; /* nothing to read */ + } + + debug_if(_ism_debug, "ISM43362 check_recv_status: id %d read_amount=%d\r\n", id, read_amount); + return read_amount; +} + +bool ISM43362::close(int id) +{ + if ((id < 0) || (id > 3)) { + debug_if(_ism_debug, "ISM43362: Wrong socket number\n"); + return false; + } + /* Set connection on this socket */ + debug_if(_ism_debug, "ISM43362: CLOSE socket id=%d\n", id); + _active_id = id; + if (!(_parser.send("P0=%d", id) && check_response())) { + return false; + } + /* close this socket */ + if (!(_parser.send("P6=0") && check_response())) { + return false; + } + return true; +} + +bool ISM43362::readable() +{ + /* not applicable with SPI api */ + return true; +} + +bool ISM43362::writeable() +{ + /* not applicable with SPI api */ + return true; +} + +void ISM43362::attach(Callback<void()> func) +{ + /* not applicable with SPI api */ +} +