wifi test
Dependencies: X_NUCLEO_IKS01A2 mbed-http
easy-connect/wifi-ism43362/ISM43362/ISM43362.cpp
- Committer:
- JMF
- Date:
- 2018-09-05
- Revision:
- 0:24d3eb812fd4
File content as of revision 0:24d3eb812fd4:
/* 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 */ }