Mbed Cloud example program for workshop in W27 2018.

Dependencies:   MMA7660 LM75B

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPWFSAxx.cpp Source File

SPWFSAxx.cpp

00001 /* SPWFSAxx Devices
00002  * Copyright (c) 2015 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "mbed_debug.h"
00018 
00019 #include "SpwfSAInterface.h" /* must be included first */
00020 #include "SPWFSAxx.h"
00021 
00022 static const char out_delim[] = {SPWFSAxx::_cr_, '\0'};
00023 
00024 SPWFSAxx::SPWFSAxx(PinName tx, PinName rx,
00025                    PinName rts, PinName cts,
00026                    SpwfSAInterface &ifce, bool debug,
00027                    PinName wakeup, PinName reset)
00028 : _serial(tx, rx, SPWFXX_DEFAULT_BAUD_RATE), _parser(&_serial, out_delim),
00029   _wakeup(wakeup, 1), _reset(reset, 1),
00030   _rts(rts), _cts(cts),
00031   _timeout(SPWF_INIT_TIMEOUT), _dbg_on(debug),
00032   _pending_sockets_bitmap(0),
00033   _network_lost_flag(false),
00034   _associated_interface(ifce),
00035   _call_event_callback_blocked(0),
00036   _callback_func(),
00037   _packets(0), _packets_end(&_packets)
00038 {
00039     memset(_pending_pkt_sizes, 0, sizeof(_pending_pkt_sizes));
00040 
00041     _serial.sigio(Callback<void()>(this, &SPWFSAxx::_event_handler));
00042     _parser.debug_on(debug);
00043     _parser.set_timeout(_timeout);
00044 
00045     /* unlikely OOBs */
00046     _parser.oob("+WIND:5:WiFi Hardware Failure", callback(this, &SPWFSAxx::_wifi_hwfault_handler));
00047     _parser.oob("+WIND:33:WiFi Network Lost", callback(this, &SPWFSAxx::_network_lost_handler_th));
00048 #if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1
00049     _parser.oob("+WIND:24:WiFi Up::", callback(this, &SPWFSAxx::_skip_oob));
00050 #endif
00051     _parser.oob("+WIND:8:Hard Fault", callback(this, &SPWFSAxx::_hard_fault_handler));
00052 
00053     /* most likely OOBs */
00054     _parser.oob(SPWFXX_OOB_ERROR, callback(this, &SPWFSAxx::_error_handler));
00055     _parser.oob("+WIND:58:Socket Closed", callback(this, &SPWFSAxx::_server_gone_handler));
00056     _parser.oob("+WIND:55:Pending Data", callback(this, &SPWFSAxx::_packet_handler_th));
00057 }
00058 
00059 bool SPWFSAxx::startup(int mode)
00060 {
00061     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00062                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00063 
00064     /*Reset module*/
00065     if(!hw_reset()) {
00066         debug_if(_dbg_on, "\r\nSPWF> HW reset failed\r\n");
00067         return false;
00068     }
00069 
00070     /* factory reset */
00071     if(!(_parser.send(SPWFXX_SEND_FWCFG) && _recv_ok()))
00072     {
00073         debug_if(_dbg_on, "\r\nSPWF> error restore factory default settings\r\n");
00074         return false;
00075     }
00076 
00077     /*switch off led*/
00078     if(!(_parser.send("AT+S.SCFG=blink_led,0") && _recv_ok()))
00079     {
00080         debug_if(_dbg_on, "\r\nSPWF> error stop blinking led (%d)\r\n", __LINE__);
00081         return false;
00082     }
00083 
00084     /*set local echo to 0*/
00085     if(!(_parser.send(SPWFXX_SEND_DISABLE_LE) && _recv_ok()))
00086     {
00087         debug_if(_dbg_on, "\r\nSPWF> error local echo set\r\n");
00088         return false;
00089     }
00090 
00091     /*set the operational rates*/
00092     if(!(_parser.send("AT+S.SCFG=wifi_opr_rate_mask,0x003FFFCF") && _recv_ok()))
00093     {
00094         debug_if(_dbg_on, "\r\nSPWF> error setting ht_mode\r\n");
00095         return false;
00096     }
00097 
00098     /*enable the 802.11n mode*/
00099     if(!(_parser.send("AT+S.SCFG=wifi_ht_mode,1") && _recv_ok()))
00100     {
00101         debug_if(_dbg_on, "\r\nSPWF> error setting operational rates\r\n");
00102         return false;
00103     }
00104 
00105     /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
00106     if(!(_parser.send("AT+S.SCFG=wifi_mode,%d", mode) && _recv_ok()))
00107     {
00108         debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set idle (%d)\r\n", __LINE__);
00109         return false;
00110     }
00111 
00112 #if defined(MBED_MAJOR_VERSION)
00113 #if !DEVICE_SERIAL_FC || (MBED_VERSION < MBED_ENCODE_VERSION(5, 7, 0))
00114     /*disable HW flow control*/
00115     if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok()))
00116     {
00117         debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n");
00118         return false;
00119     }
00120 #else // DEVICE_SERIAL_FC && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 7, 0))
00121     if((_rts != NC) && (_cts != NC)) {
00122         /*enable HW flow control*/
00123         if(!(_parser.send(SPWFXX_SEND_ENABLE_FC) && _recv_ok()))
00124         {
00125             debug_if(_dbg_on, "\r\nSPWF> error enabling HW flow control\r\n");
00126             return false;
00127         }
00128 
00129         /*configure pins for HW flow control*/
00130         _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts);
00131     } else {
00132         /*disable HW flow control*/
00133         if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok()))
00134         {
00135             debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n");
00136             return false;
00137         }
00138     }
00139 #endif // DEVICE_SERIAL_FC && (MBED_VERSION >= MBED_ENCODE_VERSION(5, 7, 0))
00140 #else // !defined(MBED_MAJOR_VERSION) - Assuming `master` branch
00141 #if !DEVICE_SERIAL_FC
00142     /*disable HW flow control*/
00143     if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok()))
00144     {
00145         debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n");
00146         return false;
00147     }
00148 #else // DEVICE_SERIAL_FC
00149     if((_rts != NC) && (_cts != NC)) {
00150         /*enable HW flow control*/
00151         if(!(_parser.send(SPWFXX_SEND_ENABLE_FC) && _recv_ok()))
00152         {
00153             debug_if(_dbg_on, "\r\nSPWF> error enabling HW flow control\r\n");
00154             return false;
00155         }
00156 
00157         /*configure pins for HW flow control*/
00158         _serial.set_flow_control(SerialBase::RTSCTS, _rts, _cts);
00159     } else {
00160         /*disable HW flow control*/
00161         if(!(_parser.send(SPWFXX_SEND_DISABLE_FC) && _recv_ok()))
00162         {
00163             debug_if(_dbg_on, "\r\nSPWF> error disabling HW flow control\r\n");
00164             return false;
00165         }
00166     }
00167 #endif // DEVICE_SERIAL_FC
00168 #endif // !defined(MBED_MAJOR_VERSION)
00169 
00170     /* Disable selected WINDs */
00171     _winds_on();
00172 
00173     /* sw reset */
00174     if(!reset()) {
00175         debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__);
00176         return false;
00177     }
00178 
00179 #ifndef NDEBUG
00180     if (!(_parser.send(SPWFXX_SEND_GET_CONS_STATE)
00181             && _recv_ok())) {
00182         debug_if(_dbg_on, "\r\nSPWF> error getting console state\r\n");
00183         return false;
00184     }
00185 
00186     if (!(_parser.send(SPWFXX_SEND_GET_CONS_SPEED)
00187             && _recv_ok())) {
00188         debug_if(_dbg_on, "\r\nSPWF> error getting console speed\r\n");
00189         return false;
00190     }
00191 
00192     if (!(_parser.send(SPWFXX_SEND_GET_HWFC_STATE)
00193             && _recv_ok())) {
00194         debug_if(_dbg_on, "\r\nSPWF> error getting hwfc state\r\n");
00195         return false;
00196     }
00197 
00198 #if (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) || defined(IDW01M1_FW_REL_35X)
00199     /* betzw: IDW01M1 FW versions <3.5 seem to have problems with the following two commands.
00200      *        For the sake of simplicity, just excluding them for IDW01M1 in general.
00201      */
00202     if (!(_parser.send(SPWFXX_SEND_GET_CONS_DELIM)
00203             && _recv_ok())) {
00204         debug_if(_dbg_on, "\r\nSPWF> error getting console delimiter\r\n");
00205         return false;
00206     }
00207 
00208     if (!(_parser.send(SPWFXX_SEND_GET_CONS_ERRS)
00209             && _recv_ok())) {
00210         debug_if(_dbg_on, "\r\nSPWF> error getting console error setting\r\n");
00211         return false;
00212     }
00213 #endif // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) || defined(IDW01M1_FW_REL_35X)
00214 
00215     if (!(_parser.send("AT+S.GCFG=sleep_enabled")
00216             && _recv_ok())) {
00217         debug_if(_dbg_on, "\r\nSPWF> error getting sleep state enabled\r\n");
00218         return false;
00219     }
00220 
00221     if (!(_parser.send("AT+S.GCFG=wifi_powersave")
00222             && _recv_ok())) {
00223         debug_if(_dbg_on, "\r\nSPWF> error getting powersave mode\r\n");
00224         return false;
00225     }
00226 
00227     if (!(_parser.send("AT+S.GCFG=standby_enabled")
00228             && _recv_ok())) {
00229         debug_if(_dbg_on, "\r\nSPWF> error getting standby state enabled\r\n");
00230         return false;
00231     }
00232 #endif
00233 
00234     return true;
00235 }
00236 
00237 bool SPWFSAxx::_wait_console_active(void) {
00238     int trials = 0;
00239 
00240     while(true) {
00241         if (_parser.recv("+WIND:0:Console active\n") && _recv_delim_lf()) {
00242             debug_if(_dbg_on, "AT^ +WIND:0:Console active\r\n");
00243             return true;
00244         }
00245         if(++trials >= SPWFXX_MAX_TRIALS) {
00246             debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__);
00247             empty_rx_buffer();
00248             return false;
00249         }
00250     }
00251 }
00252 
00253 bool SPWFSAxx::_wait_wifi_hw_started(void) {
00254     int trials = 0;
00255 
00256     while(true) {
00257         if (_parser.recv("+WIND:32:WiFi Hardware Started\n") && _recv_delim_lf()) {
00258             debug_if(_dbg_on, "AT^ +WIND:32:WiFi Hardware Started\r\n");
00259             return true;
00260         }
00261         if(++trials >= SPWFXX_MAX_TRIALS) {
00262             debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__);
00263             empty_rx_buffer();
00264             return false;
00265         }
00266     }
00267 }
00268 
00269 bool SPWFSAxx::hw_reset(void)
00270 {
00271 #if (MBED_CONF_IDW0XX1_EXPANSION_BOARD != IDW04A1) || !defined(IDW04A1_WIFI_HW_BUG_WA) // betzw: HW reset doesn't work as expected on unmodified X_NUCLEO_IDW04A1 expansion boards
00272     _reset.write(0);
00273     wait_ms(200);
00274     _reset.write(1); 
00275 #else // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) && defined(IDW04A1_WIFI_HW_BUG_WA): substitute with SW reset
00276     _parser.send(SPWFXX_SEND_SW_RESET);
00277 #endif // (MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1) && defined(IDW04A1_WIFI_HW_BUG_WA)
00278     return _wait_console_active();
00279 }
00280 
00281 bool SPWFSAxx::reset(void)
00282 {
00283     bool ret;
00284 
00285     /* save current setting in flash */
00286     if(!(_parser.send(SPWFXX_SEND_SAVE_SETTINGS) && _recv_ok()))
00287     {
00288         debug_if(_dbg_on, "\r\nSPWF> error saving configuration to flash (%s, %d)\r\n", __func__, __LINE__);
00289         return false;
00290     }
00291 
00292     if(!_parser.send(SPWFXX_SEND_SW_RESET)) return false; /* betzw - NOTE: "keep the current state and reset the device".
00293                                                                      We assume that the module informs us about the
00294                                                                      eventual closing of sockets via "WIND" asynchronous
00295                                                                      indications! So everything regarding the clean-up
00296                                                                      of these situations is handled there. */
00297 
00298     /* waiting for HW to start */
00299     ret = _wait_wifi_hw_started();
00300 
00301     return ret;
00302 }
00303 
00304 /* Security Mode
00305    None          = 0, 
00306    WEP           = 1,
00307    WPA_Personal  = 2,
00308  */
00309 bool SPWFSAxx::connect(const char *ap, const char *passPhrase, int securityMode)
00310 {
00311     int trials;
00312 
00313     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00314                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00315 
00316     //AT+S.SCFG=wifi_wpa_psk_text,%s
00317     if(!(_parser.send("AT+S.SCFG=wifi_wpa_psk_text,%s", passPhrase) && _recv_ok()))
00318     {
00319         debug_if(_dbg_on, "\r\nSPWF> error pass set\r\n");
00320         return false;
00321     } 
00322 
00323     //AT+S.SSIDTXT=%s
00324     if(!(_parser.send("AT+S.SSIDTXT=%s", ap) && _recv_ok()))
00325     {
00326         debug_if(_dbg_on, "\r\nSPWF> error ssid set\r\n");
00327         return false;
00328     }
00329 
00330     //AT+S.SCFG=wifi_priv_mode,%d
00331     if(!(_parser.send("AT+S.SCFG=wifi_priv_mode,%d", securityMode) && _recv_ok()))
00332     {
00333         debug_if(_dbg_on, "\r\nSPWF> error security mode set\r\n");
00334         return false;
00335     }
00336 
00337     /*set STA mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
00338     if(!(_parser.send("AT+S.SCFG=wifi_mode,1") && _recv_ok()))
00339     {
00340         debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set 1 (STA)\r\n");
00341         return false;
00342     }
00343 
00344     /* sw reset */
00345     if(!reset()) {
00346         debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__);
00347         return false;
00348     }
00349 
00350     trials = 0;
00351     while(true) {
00352         if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf())
00353         {
00354             if(strstr(_msg_buffer, ":24:") != NULL) { // WiFi Up
00355                 debug_if(_dbg_on, "AT^ %s\n", _msg_buffer);
00356                 if(strchr(_msg_buffer, '.') != NULL) { // IPv4 address
00357                     break;
00358                 } else {
00359                     continue;
00360                 }
00361             }
00362             if(strstr(_msg_buffer, ":40:") != NULL) { // Deauthentication
00363                 debug_if(_dbg_on, "AT~ %s\n", _msg_buffer);
00364                 if(++trials < SPWFXX_MAX_TRIALS) { // give it three trials
00365                     continue;
00366                 }
00367                 disconnect();
00368                 empty_rx_buffer();
00369                 return false;
00370             } else {
00371                 debug_if(_dbg_on, "AT] %s\n", _msg_buffer);
00372             }
00373             continue;
00374         }
00375         if(++trials >= SPWFXX_MAX_TRIALS) {
00376             debug("\r\nSPWF> ERROR: Should never happen! (%s, %d)\r\n", __func__, __LINE__);
00377             empty_rx_buffer();
00378             return false;
00379         }
00380     }
00381 
00382     return true;
00383 }
00384 
00385 bool SPWFSAxx::disconnect(void)
00386 {
00387     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00388                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00389 
00390 #if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1
00391     /*disable Wi-Fi device*/
00392     if(!(_parser.send("AT+S.WIFI=0") && _recv_ok()))
00393     {
00394         debug_if(_dbg_on, "\r\nSPWF> error disabling WiFi\r\n");
00395         return false;
00396     }
00397 #endif // IDW04A1
00398 
00399     /*set idle mode (0->idle, 1->STA,3->miniAP, 2->IBSS)*/
00400     if(!(_parser.send("AT+S.SCFG=wifi_mode,0") && _recv_ok()))
00401     {
00402         debug_if(_dbg_on, "\r\nSPWF> error WiFi mode set idle (%d)\r\n", __LINE__);
00403         return false;
00404     }
00405 
00406 #if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1
00407     /*enable Wi-Fi device*/
00408     if(!(_parser.send("AT+S.WIFI=1") && _recv_ok()))
00409     {
00410         debug_if(_dbg_on, "\r\nSPWF> error enabling WiFi\r\n");
00411         return false;
00412     }
00413 #endif // IDW04A1
00414 
00415     // reset module
00416     if(!reset()) {
00417         debug_if(_dbg_on, "\r\nSPWF> SW reset failed (%s, %d)\r\n", __func__, __LINE__);
00418         return false;
00419     }
00420 
00421     /* clean up state */
00422     _associated_interface.inner_constructor();
00423     _free_all_packets();
00424 
00425     return true;
00426 }
00427 
00428 const char *SPWFSAxx::getIPAddress(void)
00429 {
00430     unsigned int n1, n2, n3, n4;
00431 
00432     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00433                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00434 
00435     if (!(_parser.send("AT+S.STS=ip_ipaddr")
00436             && _parser.recv(SPWFXX_RECV_IP_ADDR, &n1, &n2, &n3, &n4)
00437             && _recv_ok())) {
00438         debug_if(_dbg_on, "\r\nSPWF> get IP address error\r\n");
00439         return NULL;
00440     }
00441 
00442     debug_if(_dbg_on, "AT^ ip_ipaddr = %u.%u.%u.%u\r\n", n1, n2, n3, n4);
00443 
00444     sprintf((char*)_ip_buffer,"%u.%u.%u.%u", n1, n2, n3, n4);
00445     return _ip_buffer;
00446 }
00447 
00448 const char *SPWFSAxx::getGateway(void)
00449 {
00450     unsigned int n1, n2, n3, n4;
00451 
00452     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00453                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00454 
00455     if (!(_parser.send("AT+S.STS=ip_gw")
00456             && _parser.recv(SPWFXX_RECV_GATEWAY, &n1, &n2, &n3, &n4)
00457             && _recv_ok())) {
00458         debug_if(_dbg_on, "\r\nSPWF> get gateway error\r\n");
00459         return NULL;
00460     }
00461 
00462     debug_if(_dbg_on, "AT^ ip_gw = %u.%u.%u.%u\r\n", n1, n2, n3, n4);
00463 
00464     sprintf((char*)_gateway_buffer,"%u.%u.%u.%u", n1, n2, n3, n4);
00465     return _gateway_buffer;
00466 }
00467 
00468 const char *SPWFSAxx::getNetmask(void)
00469 {
00470     unsigned int n1, n2, n3, n4;
00471 
00472     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00473                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00474 
00475     if (!(_parser.send("AT+S.STS=ip_netmask")
00476             && _parser.recv(SPWFXX_RECV_NETMASK, &n1, &n2, &n3, &n4)
00477             && _recv_ok())) {
00478         debug_if(_dbg_on, "\r\nSPWF> get netmask error\r\n");
00479         return NULL;
00480     }
00481 
00482     debug_if(_dbg_on, "AT^ ip_netmask = %u.%u.%u.%u\r\n", n1, n2, n3, n4);
00483 
00484     sprintf((char*)_netmask_buffer,"%u.%u.%u.%u", n1, n2, n3, n4);
00485     return _netmask_buffer;
00486 }
00487 
00488 int8_t SPWFSAxx::getRssi(void)
00489 {
00490     int ret;
00491 
00492     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00493                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00494 
00495     if (!(_parser.send("AT+S.PEERS=0,rx_rssi")
00496             && _parser.recv(SPWFXX_RECV_RX_RSSI, &ret)
00497             && _recv_ok())) {
00498         debug_if(_dbg_on, "\r\nSPWF> get RX rssi error\r\n");
00499         return 0;
00500     }
00501 
00502     return (int8_t)ret;
00503 }
00504 
00505 const char *SPWFSAxx::getMACAddress(void)
00506 {
00507     unsigned int n1, n2, n3, n4, n5, n6;
00508 
00509     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00510                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00511 
00512     if (!(_parser.send("AT+S.GCFG=nv_wifi_macaddr")
00513             && _parser.recv(SPWFXX_RECV_MAC_ADDR, &n1, &n2, &n3, &n4, &n5, &n6)
00514             && _recv_ok())) {
00515         debug_if(_dbg_on, "\r\nSPWF> get MAC address error\r\n");
00516         return 0;
00517     }
00518 
00519     debug_if(_dbg_on, "AT^ nv_wifi_macaddr = %x:%x:%x:%x:%x:%x\r\n", n1, n2, n3, n4, n5, n6);
00520 
00521     sprintf((char*)_mac_buffer,"%02X:%02X:%02X:%02X:%02X:%02X", n1, n2, n3, n4, n5, n6);
00522     return _mac_buffer;
00523 }
00524 
00525 bool SPWFSAxx::isConnected(void)
00526 {
00527     return _associated_interface._connected_to_network;
00528 }
00529 
00530 nsapi_size_or_error_t SPWFSAxx::send(int spwf_id, const void *data, uint32_t amount, int internal_id)
00531 {
00532     uint32_t sent = 0U, to_send;
00533     nsapi_size_or_error_t ret;
00534 
00535     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00536                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00537 
00538     _process_winds(); // perform async indication handling (to early detect eventually closed sockets)
00539 
00540     /* betzw - WORK AROUND module FW issues: split up big packages in smaller ones */
00541     for(to_send = (amount > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : amount;
00542             sent < amount;
00543             to_send = ((amount - sent) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (amount - sent)) {
00544         {
00545             BlockExecuter bh_handler(Callback<void()>(this, &SPWFSAxx::_execute_bottom_halves));
00546 
00547             // betzw - TODO: handle different errors more accurately!
00548             if (!_associated_interface._socket_is_still_connected(internal_id)) {
00549                 debug_if(_dbg_on, "\r\nSPWF> Socket not connected anymore: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__);
00550                 break;
00551             } else if(!_parser.send("AT+S.SOCKW=%d,%d", spwf_id, (unsigned int)to_send)) {
00552                 debug_if(_dbg_on, "\r\nSPWF> Sending command failed: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__);
00553                 break;
00554             } else if(_parser.write(((char*)data)+sent, (int)to_send) != (int)to_send) {
00555                 debug_if(_dbg_on, "\r\nSPWF> Sending data failed: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__);
00556                 break;
00557             } else if(!_recv_ok()) {
00558                 debug_if(_dbg_on, "\r\nSPWF> Sending did not receive OK: sent=%u, to_send=%u! (%s, %d)\r\n", sent, to_send, __func__, __LINE__);
00559                 break;
00560             }
00561         }
00562 
00563         sent += to_send;
00564     }
00565 
00566     if(sent > 0) { // `sent == 0` indicates a potential error
00567         ret = sent;
00568     } else if(amount == 0) {
00569         ret = NSAPI_ERROR_OK;
00570     } else if(_associated_interface._socket_is_still_connected(internal_id)) {
00571         ret = NSAPI_ERROR_DEVICE_ERROR;
00572     } else {
00573         ret = NSAPI_ERROR_CONNECTION_LOST;
00574     }
00575 
00576     return ret;
00577 }
00578 
00579 int SPWFSAxx::_read_len(int spwf_id) {
00580     unsigned int amount;
00581 
00582     if (!(_parser.send("AT+S.SOCKQ=%d", spwf_id)
00583             && _parser.recv(SPWFXX_RECV_DATALEN, &amount)
00584             && _recv_ok())) {
00585         debug_if(_dbg_on, "\r\nSPWF> %s failed\r\n", __func__);
00586         return SPWFXX_ERR_LEN;
00587     }
00588 
00589     if(amount > 0) {
00590         debug_if(_dbg_on, "\r\nSPWF> %s():\t\t%d:%d\r\n", __func__, spwf_id, amount);
00591     }
00592 
00593     MBED_ASSERT(((int)amount) >= 0);
00594 
00595     return (int)amount;
00596 }
00597 
00598 #define SPWFXX_WINDS_OFF "0xFFFFFFFF"
00599 
00600 void SPWFSAxx::_winds_on(void) {
00601     MBED_ASSERT(_is_event_callback_blocked());
00602 
00603     if(!(_parser.send(SPWFXX_SEND_WIND_OFF_HIGH SPWFXX_WINDS_HIGH_ON) && _recv_ok())) {
00604         debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__);
00605     }
00606     if(!(_parser.send(SPWFXX_SEND_WIND_OFF_MEDIUM SPWFXX_WINDS_MEDIUM_ON) && _recv_ok())) {
00607         debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__);
00608     }
00609     if(!(_parser.send(SPWFXX_SEND_WIND_OFF_LOW SPWFXX_WINDS_LOW_ON) && _recv_ok())) {
00610         debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__);
00611     }
00612 }
00613 
00614 /* Define beyond macro in case you want to report back failures in switching off WINDs to the caller */
00615 // #define SPWFXX_SOWF
00616 /* Note: in case of error blocking has been (tried to be) lifted */
00617 bool SPWFSAxx::_winds_off(void) {
00618     MBED_ASSERT(_is_event_callback_blocked());
00619 
00620     if (!(_parser.send(SPWFXX_SEND_WIND_OFF_LOW SPWFXX_WINDS_OFF)
00621             && _recv_ok())) {
00622         debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__);
00623 #ifdef SPWFXX_SOWF // betzw: try to continue
00624         _winds_on();
00625         return false;
00626 #endif
00627     }
00628 
00629     if (!(_parser.send(SPWFXX_SEND_WIND_OFF_MEDIUM SPWFXX_WINDS_OFF)
00630             && _recv_ok())) {
00631         debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__);
00632 #ifdef SPWFXX_SOWF // betzw: try to continue
00633         _winds_on();
00634         return false;
00635 #endif
00636     }
00637 
00638     if (!(_parser.send(SPWFXX_SEND_WIND_OFF_HIGH SPWFXX_WINDS_OFF)
00639             && _recv_ok())) {
00640         debug_if(_dbg_on, "\r\nSPWF> %s failed at line #%d\r\n", __func__, __LINE__);
00641 #ifdef SPWFXX_SOWF // betzw: try to continue
00642         _winds_on();
00643         return false;
00644 #endif
00645     }
00646 
00647     return true;
00648 }
00649 
00650 void SPWFSAxx::_execute_bottom_halves(void) {
00651     _network_lost_handler_bh();
00652     _packet_handler_bh();
00653 }
00654 
00655 void SPWFSAxx::_read_in_pending(void) {
00656     static int internal_id_cnt = 0;
00657 
00658     while(_is_data_pending()) {
00659         if(_associated_interface._socket_has_connected(internal_id_cnt)) {
00660             int spwf_id = _associated_interface._ids[internal_id_cnt].spwf_id;
00661 
00662             if(_is_data_pending(spwf_id)) {
00663                 int amount;
00664 
00665                 amount = _read_in_pkt(spwf_id, false);
00666                 if(amount == SPWFXX_ERR_OOM) { /* consider only 'SPWFXX_ERR_OOM' as non recoverable */
00667                     return;
00668                 }
00669             }
00670 
00671             if(!_is_data_pending(spwf_id)) {
00672                 internal_id_cnt++;
00673                 internal_id_cnt %= SPWFSA_SOCKET_COUNT;
00674             }
00675         } else {
00676             internal_id_cnt++;
00677             internal_id_cnt %= SPWFSA_SOCKET_COUNT;
00678         }
00679     }
00680 }
00681 
00682 /* Note: returns
00683  * 'SPWFXX_ERR_OK'   in case of success
00684  * 'SPWFXX_ERR_OOM'  in case of "out of memory"
00685  * 'SPWFXX_ERR_READ' in case of `_read_in()` error
00686  */
00687 int SPWFSAxx::_read_in_packet(int spwf_id, uint32_t amount) {
00688     struct packet *packet = (struct packet*)malloc(sizeof(struct packet) + amount);
00689     if (!packet) {
00690 #ifndef NDEBUG
00691         error("\r\nSPWF> %s(%d): Out of memory!\r\n", __func__, __LINE__);
00692 #else // NDEBUG
00693         debug("\r\nSPWF> %s(%d): Out of memory!\r\n", __func__, __LINE__);
00694 #endif
00695         debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__);
00696         return SPWFXX_ERR_OOM; /* out of memory: give up here! */
00697     }
00698 
00699     /* init packet */
00700     packet->id = spwf_id;
00701     packet->len = amount;
00702     packet->next = 0;
00703 
00704     /* read data in */
00705     if(!(_read_in((char*)(packet + 1), spwf_id, amount) > 0)) {
00706         free(packet);
00707         debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__);
00708         return SPWFXX_ERR_READ;
00709     } else {
00710         debug_if(_dbg_on, "\r\nSPWF> %s():\t%d:%d\r\n", __func__, spwf_id, amount);
00711 
00712         /* append to packet list */
00713         *_packets_end = packet;
00714         _packets_end = &packet->next;
00715 
00716         /* force call of (external) callback */
00717         _call_callback();
00718     }
00719 
00720     return SPWFXX_ERR_OK;
00721 }
00722 
00723 void SPWFSAxx::_free_packets(int spwf_id) {
00724     // check if any packets are ready for `spwf_id`
00725     for(struct packet **p = &_packets; *p;) {
00726         if ((*p)->id == spwf_id) {
00727             struct packet *q = *p;
00728             if (_packets_end == &(*p)->next) {
00729                 _packets_end = p;
00730             }
00731             *p = (*p)->next;
00732             free(q);
00733         } else {
00734             p = &(*p)->next;
00735         }
00736     }
00737 }
00738 
00739 void SPWFSAxx::_free_all_packets() {
00740     for (int spwf_id = 0; spwf_id < SPWFSA_SOCKET_COUNT; spwf_id++) {
00741         _free_packets(spwf_id);
00742     }
00743 }
00744 
00745 bool SPWFSAxx::close(int spwf_id)
00746 {
00747     bool ret = false;
00748 
00749     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00750                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* disable calling (external) callback in IRQ context */
00751 
00752     MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT)); // `spwf_id` is valid
00753 
00754     for(int retry_cnt = 0; retry_cnt < SPWFXX_MAX_TRIALS; retry_cnt++) {
00755         Timer timer;
00756         timer.start();
00757 
00758         // Flush out pending data
00759         while(true) {
00760             int amount = _read_in_pkt(spwf_id, true);
00761             if(amount < 0) { // SPWFXX error
00762                 /* empty RX buffer & try to close */
00763                 empty_rx_buffer();
00764                 break;
00765             }
00766             if(amount == 0) break; // no more data to be read
00767 
00768             /* Try to work around module API bug:
00769              * break out & try to close after 20 seconds
00770              */
00771             if(timer.read() > 20) {
00772                 break;
00773             }
00774 
00775             /* immediately free packet(s) (to avoid "out of memory") */
00776             _free_packets(spwf_id);
00777 
00778             /* interleave bottom halves */
00779             _execute_bottom_halves();
00780         }
00781 
00782         // Close socket
00783         if (_parser.send("AT+S.SOCKC=%d", spwf_id)
00784                 && _recv_ok()) {
00785             ret = true;
00786             break; // finish closing
00787         } else { // close failed
00788             debug_if(_dbg_on, "\r\nSPWF> %s failed (%d)\r\n", __func__, __LINE__);
00789             /* interleave bottom halves */
00790             _execute_bottom_halves();
00791 
00792             /* free packets */
00793             _free_packets(spwf_id);
00794         }
00795     }
00796 
00797     /* anticipate bottom halves */
00798     _execute_bottom_halves();
00799 
00800     if(ret) {
00801         /* clear pending data flag (should be redundant) */
00802         _clear_pending_data(spwf_id);
00803 
00804         /* free packets for this socket */
00805         _free_packets(spwf_id);
00806 
00807         /* reset pending data sizes */
00808         _reset_pending_pkt_sizes(spwf_id);
00809     } else {
00810         debug_if(_dbg_on, "\r\nSPWF> SPWFSAxx::close failed (%d)\r\n", __LINE__);
00811 
00812         int internal_id = _associated_interface.get_internal_id(spwf_id);
00813         if(!_associated_interface._socket_is_still_connected(internal_id)) {
00814             /* clear pending data flag (should be redundant) */
00815             _clear_pending_data(spwf_id);
00816 
00817             /* free packets for this socket */
00818             _free_packets(spwf_id);
00819 
00820             /* reset pending data sizes */
00821             _reset_pending_pkt_sizes(spwf_id);
00822 
00823             ret = true;
00824         }
00825     }
00826 
00827     return ret;
00828 }
00829 
00830 /*
00831  * Buffered serial event handler
00832  *
00833  * Note: executed in IRQ context!
00834  * Note: do not call (external) callback in IRQ context while performing critical module operations
00835  */
00836 void SPWFSAxx::_event_handler(void)
00837 {
00838     if(!_is_event_callback_blocked()) {
00839         _call_callback();
00840     }
00841 }
00842 
00843 /*
00844  * Common error handler
00845  */
00846 void SPWFSAxx::_error_handler(void)
00847 {
00848     if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) {
00849         debug_if(_dbg_on, "AT^ ERROR:%s (%d)\r\n", _msg_buffer, __LINE__);
00850     } else {
00851         debug_if(_dbg_on, "\r\nSPWF> Unknown ERROR string in SPWFSAxx::_error_handler (%d)\r\n", __LINE__);
00852     }
00853 
00854     /* force call of (external) callback */
00855     _call_callback();
00856 }
00857 
00858 /*
00859  * Handling oob ("+WIND:33:WiFi Network Lost")
00860  */
00861 void SPWFSAxx::_network_lost_handler_th(void)
00862 {
00863 #ifndef NDEBUG
00864     static unsigned int net_loss_cnt = 0;
00865     net_loss_cnt++;
00866 #endif
00867 
00868     _recv_delim_cr_lf();
00869 
00870     debug_if(_dbg_on, "AT^ +WIND:33:WiFi Network Lost\r\n");
00871 
00872 #ifndef NDEBUG
00873     debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_th: %d\r\n", net_loss_cnt);
00874 #else // NDEBUG
00875     debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_th: %d\r\n", __LINE__);
00876 #endif // NDEBUG
00877 
00878     /* set flag to signal network loss */
00879     _network_lost_flag = true;
00880 
00881     /* force call of (external) callback */
00882     _call_callback();
00883 
00884     return;
00885 }
00886 
00887 /* betzw - WORK AROUND module FW issues: split up big packages in smaller ones */
00888 void SPWFSAxx::_add_pending_packet_sz(int spwf_id, uint32_t size) {
00889     uint32_t to_add;
00890     uint32_t added = _get_cumulative_size(spwf_id);
00891 
00892     if(size <= added) { // might happen due to delayed WIND delivery
00893         debug_if(_dbg_on, "\r\nSPWF> WARNING: %s failed at line #%d\r\n", __func__, __LINE__);
00894         return;
00895     }
00896 
00897     for(to_add = ((size - added) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (size - added);
00898             added < size;
00899             to_add = ((size - added) > SPWFXX_SEND_RECV_PKTSIZE) ? SPWFXX_SEND_RECV_PKTSIZE : (size - added)) {
00900         _add_pending_pkt_size(spwf_id, added + to_add);
00901         added += to_add;
00902     }
00903 
00904     /* force call of (external) callback */
00905     _call_callback();
00906 
00907     /* set that data is pending */
00908     _set_pending_data(spwf_id);
00909 }
00910 
00911 /*
00912  * Handling oob ("+WIND:55:Pending Data")
00913  */
00914 void SPWFSAxx::_packet_handler_th(void)
00915 {
00916     int internal_id, spwf_id;
00917     int amount;
00918 
00919     /* parse out the socket id & amount */
00920     if (!(_parser.recv(SPWFXX_RECV_PENDING_DATA, &spwf_id, &amount) && _recv_delim_lf())) {
00921 #ifndef NDEBUG
00922         error("\r\nSPWF> SPWFSAxx::%s failed!\r\n", __func__);
00923 #endif
00924         return;
00925     }
00926 
00927     debug_if(_dbg_on, "AT^ +WIND:55:Pending Data:%d:%d\r\n", spwf_id, amount);
00928 
00929     /* check for the module to report a valid id */
00930     MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT));
00931 
00932     /* set that there is pending data for socket */
00933     /* NOTE: it seems as if asynchronous indications might report not up-to-date data length values
00934      *       therefore we just record the socket id without considering the `amount` of data reported!
00935      */
00936     internal_id = _associated_interface.get_internal_id(spwf_id);
00937     if(internal_id != SPWFSA_SOCKET_COUNT) {
00938         debug_if(_dbg_on, "AT^ +WIND:55:Pending Data:%d:%d - #2\r\n", spwf_id, amount);
00939         _add_pending_packet_sz(spwf_id, amount);
00940 
00941         MBED_ASSERT(_get_pending_pkt_size(spwf_id) != 0);
00942     } else {
00943         debug_if(_dbg_on, "\r\nSPWFSAxx::%s got invalid id %d\r\n", __func__, spwf_id);
00944     }
00945 }
00946 
00947 void SPWFSAxx::_network_lost_handler_bh(void)
00948 {
00949     if(!_network_lost_flag) return;
00950     _network_lost_flag = false;
00951 
00952     {
00953         bool were_connected;
00954         BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
00955                                      Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* do not call (external) callback in IRQ context as long as network is lost */
00956         Timer timer;
00957         timer.start();
00958 
00959         _parser.set_timeout(SPWF_NETLOST_TIMEOUT);
00960 
00961         were_connected = isConnected();
00962         _associated_interface._connected_to_network = false;
00963 
00964         if(were_connected) {
00965             unsigned int n1, n2, n3, n4;
00966 
00967             while(true) {
00968                 if (timer.read_ms() > SPWF_CONNECT_TIMEOUT) {
00969                     debug_if(_dbg_on, "\r\nSPWF> SPWFSAxx::_network_lost_handler_bh() #%d\r\n", __LINE__);
00970                     disconnect();
00971                     empty_rx_buffer();
00972                     goto nlh_get_out;
00973                 }
00974 
00975                 if((_parser.recv(SPWFXX_RECV_WIFI_UP, &n1, &n2, &n3, &n4)) && _recv_delim_lf()) {
00976                     debug_if(_dbg_on, "\r\nSPWF> Re-connected (%u.%u.%u.%u)!\r\n", n1, n2, n3, n4);
00977 
00978                     _associated_interface._connected_to_network = true;
00979                     goto nlh_get_out;
00980                 }
00981             }
00982         } else {
00983             debug_if(_dbg_on, "\r\nSPWF> Leaving SPWFSAxx::_network_lost_handler_bh\r\n");
00984             goto nlh_get_out;
00985         }
00986 
00987     nlh_get_out:
00988         debug_if(_dbg_on, "\r\nSPWF> Getting out of SPWFSAxx::_network_lost_handler_bh\r\n");
00989         _parser.set_timeout(_timeout);
00990 
00991         /* force call of (external) callback */
00992         _call_callback();
00993 
00994         return;
00995     }
00996 }
00997 
00998 void SPWFSAxx::_recover_from_hard_faults(void) {
00999     disconnect();
01000     empty_rx_buffer();
01001 
01002     /* force call of (external) callback */
01003     _call_callback();
01004 }
01005 
01006 /*
01007  * Handling oob ("+WIND:8:Hard Fault")
01008  */
01009 void SPWFSAxx::_hard_fault_handler(void)
01010 {
01011     _parser.set_timeout(SPWF_RECV_TIMEOUT);
01012     if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) {
01013 #ifndef NDEBUG
01014         error("\r\nSPWF> hard fault error:\r\n%s\r\n", _msg_buffer);
01015 #else // NDEBUG
01016         debug("\r\nSPWF> hard fault error:\r\n%s\r\n", _msg_buffer);
01017 #endif // NDEBUG
01018     } else {
01019 #ifndef NDEBUG
01020         error("\r\nSPWF> unknown hard fault error\r\n");
01021 #else // NDEBUG
01022         debug("\r\nSPWF> unknown hard fault error\r\n");
01023 #endif // NDEBUG
01024     }
01025 
01026     // This is most likely the best we can do to recover from this module hard fault
01027     _parser.set_timeout(SPWF_HF_TIMEOUT);
01028     _recover_from_hard_faults();
01029     _parser.set_timeout(_timeout);
01030 
01031     /* force call of (external) callback */
01032     _call_callback();
01033 }
01034 
01035 /*
01036  * Handling oob ("+WIND:5:WiFi Hardware Failure")
01037  */
01038 void SPWFSAxx::_wifi_hwfault_handler(void)
01039 {
01040     unsigned int failure_nr;
01041 
01042     /* parse out the socket id & amount */
01043     _parser.recv(":%u\n", &failure_nr);
01044     _recv_delim_lf();
01045 
01046 #ifndef NDEBUG
01047     error("\r\nSPWF> WiFi HW fault error: %u\r\n", failure_nr);
01048 #else // NDEBUG
01049     debug("\r\nSPWF> WiFi HW fault error: %u\r\n", failure_nr);
01050 
01051     // This is most likely the best we can do to recover from this module hard fault
01052     _parser.set_timeout(SPWF_HF_TIMEOUT);
01053     _recover_from_hard_faults();
01054     _parser.set_timeout(_timeout);
01055 #endif // NDEBUG
01056 
01057     /* force call of (external) callback */
01058     _call_callback();
01059 }
01060 
01061 /*
01062  * Handling oob ("+WIND:58:Socket Closed")
01063  * when server closes a client connection
01064  *
01065  * NOTE: When a socket client receives an indication about socket server gone (only for TCP sockets, WIND:58),
01066  *       the socket connection is NOT automatically closed!
01067  */
01068 void SPWFSAxx::_server_gone_handler(void)
01069 {
01070     int spwf_id, internal_id;
01071 
01072     if(!(_parser.recv(SPWFXX_RECV_SOCKET_CLOSED, &spwf_id) && _recv_delim_lf())) {
01073 #ifndef NDEBUG
01074         error("\r\nSPWF> SPWFSAxx::%s failed!\r\n", __func__);
01075 #endif
01076         goto _get_out;
01077     }
01078 
01079     debug_if(_dbg_on, "AT^ +WIND:58:Socket Closed:%d\r\n", spwf_id);
01080 
01081     /* check for the module to report a valid id */
01082     MBED_ASSERT(((unsigned int)spwf_id) < ((unsigned int)SPWFSA_SOCKET_COUNT));
01083 
01084     /* only set `server_gone`
01085      * user still can receive data & must still explicitly close the socket
01086      */
01087     internal_id = _associated_interface.get_internal_id(spwf_id);
01088     if(internal_id != SPWFSA_SOCKET_COUNT) {
01089         _associated_interface._ids[internal_id].server_gone = true;
01090     }
01091 
01092 _get_out:
01093     /* force call of (external) callback */
01094     _call_callback();
01095 }
01096 
01097 #if MBED_CONF_IDW0XX1_EXPANSION_BOARD == IDW04A1
01098 /*
01099  * Handling oob (currently only for "+WIND:24:WiFi Up::")
01100  */
01101 void SPWFSAxx::_skip_oob(void)
01102 {
01103     if(_parser.recv("%255[^\n]\n", _msg_buffer) && _recv_delim_lf()) {
01104         debug_if(_dbg_on, "AT^ +WIND:24:WiFi Up::%s\r\n", _msg_buffer);
01105     } else {
01106         debug_if(_dbg_on, "\r\nSPWF> Invalid string in SPWFSAxx::_skip_oob (%d)\r\n", __LINE__);
01107     }
01108 }
01109 #endif
01110 
01111 void SPWFSAxx::setTimeout(uint32_t timeout_ms)
01112 {
01113     _timeout = timeout_ms;
01114     _parser.set_timeout(timeout_ms);
01115 }
01116 
01117 void SPWFSAxx::attach(Callback<void()> func)
01118 {
01119     _callback_func = func; /* do not call (external) callback in IRQ context during critical module operations */
01120 }
01121 
01122 /**
01123  *  Recv Function
01124  */
01125 int32_t SPWFSAxx::recv(int spwf_id, void *data, uint32_t amount, bool datagram)
01126 {
01127     BlockExecuter bh_handler(Callback<void()>(this, &SPWFSAxx::_execute_bottom_halves));
01128 
01129     while (true) {
01130         /* check if any packets are ready for us */
01131         for (struct packet **p = &_packets; *p; p = &(*p)->next) {
01132             if ((*p)->id == spwf_id) {
01133                 debug_if(_dbg_on, "\r\nSPWF> Read done on ID %d and length of packet is %d\r\n",spwf_id,(*p)->len);
01134                 struct packet *q = *p;
01135 
01136                 MBED_ASSERT(q->len > 0);
01137 
01138                 if(datagram) { // UDP => always remove pkt size
01139                     // will always consume a whole pending size
01140                     uint32_t ret;
01141 
01142                     debug_if(_dbg_on, "\r\nSPWF> %s():\t\t\t%d:%d (datagram)\r\n", __func__, spwf_id, q->len);
01143 
01144                     ret = (amount < q->len) ? amount : q->len;
01145                     memcpy(data, q+1, ret);
01146 
01147                     if (_packets_end == &(*p)->next) {
01148                         _packets_end = p;
01149                     }
01150                     *p = (*p)->next;
01151                     free(q);
01152 
01153                     return ret;
01154                 } else { // TCP
01155                     if (q->len <= amount) { // return and remove full packet
01156                         memcpy(data, q+1, q->len);
01157 
01158                         if (_packets_end == &(*p)->next) {
01159                             _packets_end = p;
01160                         }
01161                         *p = (*p)->next;
01162                         uint32_t len = q->len;
01163                         free(q);
01164 
01165                         return len;
01166                     } else { // `q->len > amount`, return only partial packet
01167                         if(amount > 0) {
01168                             memcpy(data, q+1, amount);
01169                             q->len -= amount;
01170                             memmove(q+1, (uint8_t*)(q+1) + amount, q->len);
01171                         }
01172 
01173                         return amount;
01174                     }
01175                 }
01176             }
01177         }
01178 
01179         /* check for pending data on module */
01180         {
01181             int len;
01182 
01183             len = _read_in_pkt(spwf_id, false);
01184             if(len <= 0)  { /* SPWFXX error or no more data to be read */
01185                 return -1;
01186             }
01187         }
01188     }
01189 }
01190 
01191 void SPWFSAxx::_process_winds(void) {
01192     do {
01193         if(_parser.process_oob()) {
01194             /* nothing else to do! */;
01195         } else {
01196             debug_if(_dbg_on, "%s():\t\tNo (more) oob's found!\r\n", __func__);
01197             return; // no (more) oob's found
01198         }
01199     } while(true);
01200 }
01201 
01202 /* Note: returns
01203  * '>=0'             in case of success, amount of read in data (in bytes)
01204  * 'SPWFXX_ERR_OOM'  in case of "out of memory"
01205  * 'SPWFXX_ERR_READ' in case of other `_read_in_packet()` error
01206  * 'SPWFXX_ERR_LEN'  in case of `_read_len()` error
01207  */
01208 int SPWFSAxx::_read_in_pkt(int spwf_id, bool close) {
01209     int pending;
01210     uint32_t wind_pending;
01211     BlockExecuter netsock_wa_obj(Callback<void()>(this, &SPWFSAxx::_unblock_event_callback),
01212                                  Callback<void()>(this, &SPWFSAxx::_block_event_callback)); /* do not call (external) callback in IRQ context while receiving */
01213 
01214     _process_winds(); // perform async indication handling
01215 
01216     if(close) { // read in all data
01217         wind_pending = pending = _read_len(spwf_id); // triggers also async indication handling!
01218 
01219         if(pending > 0) {
01220             /* reset pending data sizes */
01221             _reset_pending_pkt_sizes(spwf_id);
01222             /* create new entry for pending size */
01223             _add_pending_pkt_size(spwf_id, (uint32_t)pending);
01224 #ifndef NDEBUG
01225             wind_pending = _get_pending_pkt_size(spwf_id);
01226             MBED_ASSERT(pending == (int)wind_pending);
01227 #endif
01228         } else if(pending < 0) {
01229             debug_if(_dbg_on, "\r\nSPWF> %s(), #%d:`_read_len()` failed (%d)!\r\n", __func__, __LINE__, pending);
01230         }
01231     } else { // only read in already notified data
01232         pending = wind_pending = _get_pending_pkt_size(spwf_id);
01233         if(pending == 0) { // special handling for no packets pending (to WORK AROUND missing WINDs)!
01234             pending = _read_len(spwf_id); // triggers also async indication handling!
01235 
01236             if(pending > 0) {
01237                 _process_winds(); // perform async indication handling (again)
01238                 wind_pending = _get_pending_pkt_size(spwf_id);
01239 
01240                 if(wind_pending == 0) {
01241                     /* betzw - WORK AROUND module FW issues: create new entry for pending size */
01242                     debug_if(_dbg_on, "%s():\t\tAdd packet w/o WIND (%d)!\r\n", __func__, pending);
01243                     _add_pending_packet_sz(spwf_id, (uint32_t)pending);
01244 
01245                     pending = wind_pending = _get_pending_pkt_size(spwf_id);
01246                     MBED_ASSERT(wind_pending > 0);
01247                 }
01248             } else if(pending < 0) {
01249                 debug_if(_dbg_on, "\r\nSPWF> %s(), #%d:`_read_len()` failed (%d)!\r\n", __func__, __LINE__, pending);
01250             }
01251         }
01252     }
01253 
01254     if((pending > 0) && (wind_pending > 0)) {
01255         int ret = _read_in_packet(spwf_id, wind_pending);
01256         if(ret < 0) { /* "out of memory" or `_read_in_packet()` error */
01257             /* we do not know if data is still pending at this point
01258                but leaving the pending data bit set might lead to an endless loop */
01259             _clear_pending_data(spwf_id);
01260             /* also reset pending data sizes */
01261             _reset_pending_pkt_sizes(spwf_id);
01262 
01263             return ret;
01264         }
01265 
01266         if((_get_cumulative_size(spwf_id) == 0) && (pending <= (int)wind_pending)) {
01267             _clear_pending_data(spwf_id);
01268         }
01269     } else if(pending < 0) { /* 'SPWFXX_ERR_LEN' error */
01270         MBED_ASSERT(pending == SPWFXX_ERR_LEN);
01271         /* we do not know if data is still pending at this point
01272            but leaving the pending data bit set might lead to an endless loop */
01273         _clear_pending_data(spwf_id);
01274         /* also reset pending data sizes */
01275         _reset_pending_pkt_sizes(spwf_id);
01276 
01277         return pending;
01278     } else if(pending == 0) {
01279         MBED_ASSERT(wind_pending == 0);
01280         _clear_pending_data(spwf_id);
01281     } else if(wind_pending == 0) { // `pending > 0`
01282         /* betzw: should never happen! */
01283         MBED_ASSERT(false);
01284     }
01285 
01286     return (int)wind_pending;
01287 }