Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
WizFi310.cpp
00001 /* 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 /** 00018 ****************************************************************************** 00019 * @file WizFi310.cpp 00020 * @author Gateway Team 00021 * @brief Implementation file of the WizFi310 WiFi Device 00022 ****************************************************************************** 00023 * @attention 00024 * 00025 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS 00026 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE 00027 * TIME. AS A RESULT, WIZnet SHALL NOT BE HELD LIABLE FOR ANY 00028 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING 00029 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 00030 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. 00031 * 00032 * <h2><center>© COPYRIGHT 2017 WIZnet Co.,Ltd.</center></h2> 00033 ****************************************************************************** 00034 */ 00035 00036 /* 00037 * Notes: 00038 * Assumptions: 00039 * - command terminations are "[OK]" or "[ERROR%[^\]]]" . 00040 * 00041 * Notes: 00042 * - reception notification may arrive at anytime even in the middle of a response such as wstatus report. 00043 * 00044 * Strategies: 00045 * - All reads to the serial line are done in the event queue thread context 00046 * - All callbacks are invoked from the event queue thread context. 00047 * - A limit is set to the amount of received payload. 00048 * - If hardware flow control (hwfc) is present, any further reception/command will be paused until the buffer gets read. 00049 * - If no hwfc is available, the affected socket gets closed and the incomming packets are ignored/dropped. 00050 * 00051 * Failure handling : 00052 * - If a command times out, the module is considered out of sync and operations are stopped until next module reset. 00053 * - If an unrecognized sequence of characters is received the driver stops all operation until 00054 * a reset is operated. This is to prevent any risk of received data being interpreted as being module's response when it is not. 00055 * 00056 * Known issues : 00057 * - Ideally the reset should be hardware as detection through the greeting message may be spooffed by malicious incoming data. 00058 * - Because the module may send a reception event at anytime (even in the middle of a reception) if an SSID or some other 00059 * user/envirenmentaly controled input contains something similar to the recv header, it may open gate to malicious packet 00060 * injection. 00061 * 00062 * Author: Wilfried Chauveau 00063 */ 00064 00065 /** 00066 * @TODO: 00067 * - [ ] analyze event queue usage and adjust its default size. 00068 * - [ ] analyze dispatch thread usage and adjust its default stack size. 00069 * - [ ] overhaul the event_serial & recv_state_update functions 00070 * - [ ] review error detection & handling & make sure all case are covered. 00071 * - [ ] complete doxygenation 00072 * - [ ] add support for non-dhcp/static ip mode 00073 * - [ ] add support for listen socket 00074 * - [ ] add support for thread safe ip/rssi/gateway reading 00075 */ 00076 00077 #include "mbed.h" 00078 #include "mbed_trace.h" 00079 #include "WizFi310.h" 00080 #include "DigitalOut.h" 00081 00082 #define TRACE_GROUP "WZFI" 00083 00084 #define WIZFI310_DEFAULT_BAUD_RATE 115200 00085 00086 #define AT_CMD_PARSER_DEFAULT_TIMEOUT 500 00087 #define AT_CMD_PARSER_INIT_TIMEOUT 1000 00088 #define AT_CMD_PARSER_RECV_TIMEOUT 20000 00089 00090 #define send_command(...) { trace_cmd(__VA_ARGS__); m_serial.printf(__VA_ARGS__); } 00091 00092 using namespace mbed; 00093 00094 // ================================================================================================= 00095 // Utility functions 00096 static void consume(uint8_t *to, uint8_t *from, volatile uint32_t &from_len, uint32_t amount) 00097 { 00098 memcpy(to, from, amount); 00099 from_len -= amount; 00100 memmove(from, from + amount, from_len); 00101 } 00102 00103 // ================================================================================================= 00104 // Driver implementation 00105 WizFi310::WizFi310(PinName tx, PinName rx, PinName rts, PinName cts, PinName rst) : 00106 m_rst(rst), m_rts(rts), m_cts(cts), m_nrst_pin(rst, 0), 00107 m_serial(tx, rx, WIZFI310_DEFAULT_BAUD_RATE), 00108 m_has_hwfc((rts != NC) && (cts != NC)), 00109 m_rx_event_id(0), m_attached(false), m_isr_buf_len(0), m_line_buf_len(0), 00110 m_active_action(ActionBlocked), 00111 m_recv_state(Unknown), 00112 m_greetings_cbk(NULL), m_on_cmd_end(NULL), 00113 m_data_to_receive(0), m_pending_packet(NULL), m_pending_socket(NULL), m_heap_used(0), 00114 m_thread(osPriorityNormal, MBED_CONF_WIZFI310_STACKSIZE, NULL, "wizfi310_driver"), 00115 m_event_queue(MBED_CONF_WIZFI310_EVENT_QUEUE_SIZE), 00116 m_connection_status(NSAPI_STATUS_DISCONNECTED), 00117 m_dhcp(true) 00118 { 00119 if (rst != NC) { 00120 m_nrst_pin = 0; // force reset on instanciation to match the default states. 00121 } 00122 00123 m_thread.start(Callback<void()>(&m_event_queue, &EventQueue::dispatch_forever)); 00124 m_event_queue.call_every(2000, this, &WizFi310::heart_beat); 00125 } 00126 00127 WizFi310::~WizFi310() 00128 { 00129 // TODO: we may want to gracefully shut down sockets 00130 // we may also want to gracefully disconnect the device and activate the 00131 // hw reset if any was provided. 00132 m_event_queue.break_dispatch(); 00133 m_thread.join(); 00134 } 00135 00136 void WizFi310::attach(Callback<void(nsapi_connection_status_t)> status_change_cb) 00137 { 00138 m_on_status_change = status_change_cb; 00139 } 00140 00141 bool WizFi310::dhcp(bool enabled) 00142 { 00143 // We should probably not accept a true here if the other parameters are not set. 00144 m_dhcp = enabled; 00145 return m_dhcp; 00146 } 00147 00148 nsapi_error_t WizFi310::scan (Callback<void(nsapi_wifi_ap_t *)> ap_cb) 00149 { 00150 core_util_critical_section_enter(); 00151 action_t action = (action_t)m_active_action; 00152 if ((action == ActionNone) || (action == ActionBlocked)) { 00153 m_active_action = ActionDoScan; 00154 core_util_critical_section_exit(); 00155 } else { 00156 core_util_critical_section_exit(); 00157 return NSAPI_ERROR_WOULD_BLOCK; 00158 } 00159 00160 m_scan_ap_cbk = ap_cb; 00161 00162 if (action == ActionBlocked) { 00163 m_event_queue.call(this, &WizFi310::do_reset); 00164 } else { 00165 m_event_queue.call(this, &WizFi310::do_scan); 00166 } 00167 00168 return NSAPI_ERROR_IN_PROGRESS; 00169 } 00170 00171 nsapi_error_t WizFi310::connect(const char *ap, const char *passPhrase, const char *sec) 00172 { 00173 tr_info("%s|%s setting credentials: (%s) \"%s\":\"%s\"", recv_state2str(m_recv_state), action2str((action_t)m_active_action), sec, ap, passPhrase); 00174 00175 if ((ap == NULL) || (strlen(ap) == 0)) { 00176 return NSAPI_ERROR_NO_SSID; 00177 } 00178 00179 if (m_connection_status == NSAPI_STATUS_GLOBAL_UP) { 00180 return NSAPI_ERROR_OK; 00181 } 00182 00183 core_util_critical_section_enter(); 00184 action_t action = (action_t)m_active_action; 00185 if ((action != ActionNone) && (action != ActionBlocked)) { 00186 core_util_critical_section_exit(); 00187 return NSAPI_ERROR_WOULD_BLOCK; 00188 } 00189 m_active_action = ActionDoConnect; 00190 core_util_critical_section_exit(); 00191 00192 this->set_connection_status(NSAPI_STATUS_CONNECTING); 00193 00194 m_cmd_ctx.connect.ap = ap; 00195 m_cmd_ctx.connect.pw = passPhrase; 00196 m_cmd_ctx.connect.sec = sec; 00197 m_cmd_ctx.connect.attempt = 0; 00198 00199 if (action == ActionBlocked) { 00200 m_event_queue.call(this, &WizFi310::do_reset); 00201 } else { 00202 m_event_queue.call(this, &WizFi310::do_set_access_point); 00203 } 00204 // TODO: Do we want a time out there ? 00205 return NSAPI_ERROR_IN_PROGRESS; 00206 } 00207 00208 nsapi_error_t WizFi310::disconnect() 00209 { 00210 if (m_connection_status == NSAPI_STATUS_DISCONNECTED) { 00211 return NSAPI_ERROR_NO_CONNECTION; 00212 } 00213 uint32_t expected_current = ActionNone; 00214 if (!core_util_atomic_cas_u32(&m_active_action, &expected_current, ActionDoDisconnect)) { 00215 return NSAPI_ERROR_WOULD_BLOCK; 00216 } 00217 00218 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::leave_done); 00219 send_command("AT+WLEAVE\r"); 00220 return NSAPI_ERROR_IN_PROGRESS; 00221 } 00222 00223 int WizFi310::open(const char *type, const char *addr, int port, Callback<void(void *, socket_event_t, socket_event_data_t &)> callback, void *data) 00224 { 00225 uint32_t expected = ActionNone; 00226 tr_debug("::open(%s, %s, %d){%s|%s}", type, addr, port, recv_state2str(m_recv_state), action2str((action_t)m_active_action)); 00227 if (!core_util_atomic_cas_u32(&m_active_action, &expected, ActionDoSOpen)) { 00228 return NSAPI_ERROR_WOULD_BLOCK; 00229 } 00230 00231 // try to guess the id used. 00232 int id = 0; 00233 socket_t *s = NULL; 00234 for (; id < WIZFI310_SOCKET_COUNT; id++) { 00235 s = &m_sockets[id]; 00236 if (s->status == socket_t::StatusDisconnected) { 00237 break; 00238 } 00239 } 00240 if (id < WIZFI310_SOCKET_COUNT) { 00241 s->mutex.lock(); 00242 s->reset(); 00243 s->status = socket_t::StatusConnecting; 00244 s->cbk = callback; 00245 s->data = data; 00246 s->mutex.unlock(); 00247 00248 m_cmd_ctx.sopen.s = s; 00249 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::sopen_done); 00250 send_command("AT+SCON=O,%s,%s,%d,,0\r", type, addr, port); 00251 // TODO: shall we setup a time out there ? 00252 tr_info("expecting connect on: %d", id); 00253 } else { 00254 end_action(); 00255 id = -1; 00256 } 00257 return id; 00258 } 00259 00260 nsapi_error_t WizFi310::send(int id, const void *data, uint32_t amount) 00261 { 00262 if ((id > 7) || (id < 0) || (data == NULL)) { 00263 return NSAPI_ERROR_PARAMETER; 00264 } 00265 if (amount == 0) { 00266 return NSAPI_ERROR_OK; 00267 } 00268 00269 uint32_t expected = ActionNone; 00270 if (!core_util_atomic_cas_u32(&m_active_action, &expected, ActionDoSSend)) { 00271 return NSAPI_ERROR_WOULD_BLOCK; 00272 } 00273 socket_t *s = &m_sockets[id]; 00274 00275 if (s->status != socket_t::StatusConnected) { 00276 end_action(); 00277 return NSAPI_ERROR_NO_CONNECTION; 00278 } 00279 00280 m_cmd_ctx.ssend.s = s; 00281 m_cmd_ctx.ssend.data = data; 00282 m_cmd_ctx.ssend.amount = amount; 00283 m_cmd_ctx.ssend.did_send = false; 00284 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::ssend_done); 00285 send_command("AT+SSEND=%d,,,%lu\r", id, amount); 00286 return NSAPI_ERROR_IN_PROGRESS; 00287 } 00288 00289 void WizFi310::close(int id) 00290 { 00291 tr_info("::close(%d)", id); 00292 if ((id < 0) || (id > 7)) { 00293 return; 00294 } 00295 00296 socket_t *s = &m_sockets[id]; 00297 // detach callbacks 00298 s->mutex.lock(); 00299 s->cbk = NULL; 00300 s->data = NULL; 00301 s->mutex.unlock(); 00302 int evtid = m_event_queue.call(this, &WizFi310::do_sclose, id); 00303 tr_debug("enqueue do_sclose: %d", evtid); 00304 MBED_ASSERT(evtid != 0); 00305 } 00306 00307 // ================================================================================================= 00308 // private methods 00309 void WizFi310::heart_beat() 00310 { 00311 tr_debug("%s|%s attached: %d rxevtid: %d", recv_state2str(m_recv_state), action2str((action_t)m_active_action), m_attached, m_rx_event_id); 00312 if (m_data_to_receive != 0) { 00313 tr_debug("pending socket: %lu to_recv: %lu", (((uint32_t)m_pending_socket) - (uint32_t)(m_sockets)) / sizeof(socket_t), m_data_to_receive); 00314 } 00315 00316 if (m_rx_event_id != 0) { 00317 tr_debug("tick: %u time left: %d", m_event_queue.tick(), m_event_queue.time_left(m_rx_event_id)); 00318 } 00319 tr_debug("isr_buf_len: %lu line: (%lu) %.*s", m_isr_buf_len, m_line_buf_len, m_line_buf_len, m_line_buf); 00320 00321 // TODO: This shall not be required and is here solely for debug purposed. 00322 // attach serial 00323 // if it has been detached, force enqueueing the serial_event (could aswell call it from here ...) 00324 if (!m_attached) { 00325 m_attached = true; 00326 m_serial.attach(Callback<void()>(this, &WizFi310::serial_isr)); 00327 } 00328 core_util_critical_section_enter(); 00329 if (m_rx_event_id == 0) { 00330 // TODO: If m_rx_event_id == 0 means that we failed at scheduling the event the previous time. 00331 // Shall we loop until it's actually enqueued ? 00332 m_rx_event_id = m_event_queue.call(this, &WizFi310::serial_event); 00333 } 00334 core_util_critical_section_exit(); 00335 } 00336 00337 void WizFi310::set_connection_status(nsapi_connection_status_t status) 00338 { 00339 bool has_changed = m_connection_status != status; 00340 if (has_changed) { 00341 tr_debug("Wifi status change: %d", status); 00342 m_connection_status = status; 00343 if (m_on_status_change) { 00344 m_on_status_change(status); 00345 } 00346 } 00347 } 00348 00349 // Runs from an isr context. 00350 // This kind of emulates what a dma would do 00351 void WizFi310::serial_isr() 00352 { 00353 if (m_rx_event_id == 0) { 00354 // TODO: If m_rx_event_id == 0 means that we failed at scheduling the event the previous time. 00355 // Shall we loop until it's actually enqueued ? 00356 m_rx_event_id = m_event_queue.call(this, &WizFi310::serial_event); 00357 } 00358 if ((m_isr_buf_len >= MBED_CONF_WIZFI310_RX_BUFFER_SIZE) && m_has_hwfc) { 00359 m_serial.attach(NULL); // if buffer full, detach isr, it will be reattached later 00360 m_attached = false; 00361 return; 00362 } 00363 int input = -1; 00364 // .getc() contains a loop on readable. we don't want to get stuck in it from an interrupt. 00365 if (m_serial.readable()) { 00366 input = m_serial.getc(); 00367 } 00368 if (input < 0) { 00369 // TODO: do we want to catch that ? 00370 // Most probably yes. 00371 return; 00372 } 00373 00374 if (m_isr_buf_len < MBED_CONF_WIZFI310_RX_BUFFER_SIZE) { 00375 m_isr_buf[m_isr_buf_len] = (char)input; 00376 m_isr_buf_len += 1; 00377 } else { 00378 // Overrun is flagged in the serial_event. 00379 } 00380 } 00381 00382 void WizFi310::fatal_error(const char *msg) 00383 { 00384 m_active_action = ActionBlocked; 00385 00386 m_serial.attach(NULL); 00387 m_attached = false; 00388 00389 m_recv_state = ResetRequired; 00390 00391 tr_error("Fatal error: %s", msg); 00392 } 00393 00394 // runs from the global event queue context. 00395 void WizFi310::serial_event() 00396 { 00397 m_rx_event_id = 0; 00398 while (true) { 00399 tr_debug("isr_buf_len: %lu line: (%lu) %.*s", m_isr_buf_len, m_line_buf_len, m_line_buf_len, m_line_buf); 00400 uint8_t *buf = m_work_buf; 00401 uint32_t len = 0; 00402 bool has_line = (m_line_buf_len != 0) && ((m_line_buf[m_line_buf_len - 1] == '\r') || (m_line_buf[m_line_buf_len - 1] == '\n')); 00403 bool has_recv = false; 00404 00405 if (!has_line) { 00406 // TODO: simplify/rationalize this, it is too complex to sit here 00407 // the ratio indentation/line count is 00408 core_util_critical_section_enter(); 00409 switch (m_recv_state) { 00410 case ResetRequired: 00411 break; 00412 case Recv: { 00413 if ((m_pending_packet != NULL) || !m_has_hwfc) { 00414 // extract as much as needed to exhaust the current packet. 00415 if (m_data_to_receive > m_isr_buf_len) { 00416 len = m_isr_buf_len; 00417 } else { 00418 len = m_data_to_receive; 00419 } 00420 } 00421 00422 // consume len from m_isr_buf 00423 // has no effect is len == 0. 00424 consume(buf, m_isr_buf, m_isr_buf_len, len); 00425 break; 00426 } 00427 case RecvEnd: { 00428 if (m_isr_buf_len >= 2) { 00429 m_isr_buf_len -= 2; 00430 memmove(m_isr_buf, m_isr_buf + 2, m_isr_buf_len); 00431 core_util_critical_section_exit(); 00432 m_recv_state = m_prev_state; 00433 continue; 00434 } 00435 break; 00436 } 00437 default: { 00438 // search for recv event or eol 00439 uint8_t *ptr = NULL; 00440 for (uint32_t i = 0; i < m_isr_buf_len; i++) { 00441 if ((m_isr_buf[i] == '{') || (m_isr_buf[i] == '\r') || (m_isr_buf[i] == '\n')) { 00442 ptr = &m_isr_buf[i]; 00443 break; 00444 } 00445 } 00446 00447 if (ptr != NULL) { 00448 has_recv = *ptr == '{'; 00449 has_line = !has_recv; 00450 len = ptr - m_isr_buf; 00451 00452 // if we matched an eol, then include it in the copy. 00453 if (has_line) { 00454 len += 1; 00455 } 00456 } 00457 if ((m_line_buf_len + len) > MBED_CONF_WIZFI310_LINE_BUFFER_SIZE) { 00458 core_util_critical_section_exit(); 00459 this->fatal_error("Line buffer overrun"); 00460 return; 00461 } 00462 consume(m_line_buf + m_line_buf_len, m_isr_buf, m_isr_buf_len, len); 00463 m_line_buf_len += len; 00464 00465 if (m_isr_buf[0] == '{') { 00466 ptr = (uint8_t *)memchr(m_isr_buf, '}', m_isr_buf_len); 00467 has_recv &= ptr != NULL; 00468 if (has_recv) { 00469 len = (ptr - m_isr_buf) + 1; 00470 consume(buf, m_isr_buf, m_isr_buf_len, len); 00471 } else { 00472 len = 0; 00473 } 00474 } 00475 if (!has_line && !has_recv && (m_isr_buf_len == MBED_CONF_WIZFI310_RX_BUFFER_SIZE)) { 00476 core_util_critical_section_exit(); 00477 this->fatal_error("rx buffer overrun"); 00478 return; 00479 } 00480 break; 00481 } 00482 } 00483 core_util_critical_section_exit(); 00484 } 00485 00486 if (!has_recv && has_line) { 00487 buf = m_line_buf; 00488 len = m_line_buf_len; 00489 } 00490 00491 if ((m_recv_state == Recv) && ((len != 0) || (m_pending_packet == NULL))) { 00492 // if we are in recv mode and we either read something or we need to allocated a packet, proceed to the recv_state_update method. 00493 if (this->recv_state_update((char *)buf, len)) { 00494 // if recv_state_update returns false, we exit the loop and come back later. 00495 // this shall only happen if m_recv_state == recv & m_pending_packet == null. 00496 break; 00497 } 00498 } else if (has_line || has_recv) { 00499 // if we found an recv header or a complete line 00500 // clear the eol if any 00501 // proceed to recv_state_update. 00502 if ((buf[0] != '{') && ((buf[len - 1] == '\n') || (buf[len - 1] == '\r'))) { 00503 len -= 1; // remove eol byte from the line. 00504 } 00505 if (len != 0) { 00506 buf[len] = '\0'; 00507 this->recv_state_update((char *)buf, len); 00508 } 00509 if (has_line) { 00510 m_line_buf_len = 0; 00511 } 00512 } else { 00513 // we're done (not enough data), break the loop. 00514 break; 00515 } 00516 } 00517 m_attached = true; 00518 m_serial.attach(Callback<void()>(this, &WizFi310::serial_isr)); 00519 } 00520 00521 // TODO: make this cleaner, 00522 // An array of callback using the recv_state_t as an index could be a nicer dispatch tool than this big switch. 00523 bool WizFi310::recv_state_update(char *buf, uint32_t len) 00524 { 00525 int id; 00526 char fw_rev[9] = {0}; 00527 char ip[16] = {0}; 00528 uint16_t port; 00529 uint32_t plen; 00530 00531 if (m_recv_state != Recv) { 00532 tr_info("%s|%s: received: (%3lu) %.*s", recv_state2str(m_recv_state), action2str((action_t)m_active_action), len, (int)len, buf); 00533 if (this->parse_recv(buf, len, id, ip, port, plen)) { 00534 // tr_debug("recv: %d (%s:%hu): %lu", id, ip, port, plen); 00535 m_data_to_receive = plen; 00536 m_pending_socket = &m_sockets[id]; 00537 // TODO: update socket's ip/port 00538 m_prev_state = m_recv_state; 00539 m_recv_state = Recv; 00540 return false; 00541 } 00542 00543 } else { 00544 // tr_info("%s|%s: received: (%3lu) %s", recv_state2str(m_recv_state), action2str((action_t)m_active_action), len, print_buf(buf, len)); 00545 // tr_info("%s|%s: received: (%3lu) <bin>", recv_state2str(m_recv_state), action2str((action_t)m_active_action), len); 00546 } 00547 00548 switch (m_recv_state) { 00549 case Unknown: { 00550 if (this->parse_greeting(buf, len, fw_rev)) { 00551 if (m_greetings_cbk) { 00552 m_greetings_cbk(fw_rev); 00553 } 00554 } else { 00555 // ignore unexpected messaages 00556 } 00557 break; 00558 } 00559 case LinkUpIP: { 00560 if (this->parse_linkup_ip(buf, len, m_ip_buffer)) { 00561 m_recv_state = LinkUpGW; 00562 } else { 00563 tr_warn("unexpected: %.*s", (int)len, buf); 00564 this->fatal_error("Unexpected message"); 00565 } 00566 break; 00567 } 00568 case LinkUpGW: { 00569 if (this->parse_linkup_gw(buf, len, m_gateway_buffer)) { 00570 this->set_connection_status(NSAPI_STATUS_GLOBAL_UP); 00571 m_recv_state = Ready; 00572 } else { 00573 tr_warn("unexpected: %.*s", (int)len, buf); 00574 this->fatal_error("Unexpected message"); 00575 } 00576 break; 00577 } 00578 case Status: { 00579 int32_t t; 00580 if (this->parse_status(buf, len, m_ip_buffer, m_gateway_buffer, m_mac_buffer, t)) { 00581 m_rssi = t; 00582 m_recv_state = Ready; 00583 } else { 00584 tr_warn("Unexpected: %.*s", (int)len, buf); 00585 this->fatal_error("Unexpected message"); 00586 } 00587 break; 00588 } 00589 case Scan: { 00590 nsapi_wifi_ap_t ap = {0}; 00591 if (this->parse_ap(buf, len, &ap)) { 00592 if (m_scan_ap_cbk) { 00593 m_scan_ap_cbk(&ap); 00594 } 00595 } else if (strcmp(buf, "[OK]") == 0) { 00596 if (m_scan_ap_cbk) { 00597 m_scan_ap_cbk(NULL); 00598 } 00599 this->end_action(); 00600 m_recv_state = Ready; 00601 } else { 00602 tr_warn("Unexpected: %.*s", (int)len, buf); 00603 this->fatal_error("Unexpected message"); 00604 } 00605 break; 00606 } 00607 case Recv: { 00608 if (m_pending_packet == NULL) { 00609 if ((m_heap_used + m_data_to_receive) >= MBED_CONF_WIZFI310_MAX_HEAP_USAGE) { 00610 tr_warn("cannot allocate yet, wait for next attempt"); 00611 return true; 00612 } else { 00613 m_pending_packet = Packet::new_packet(m_data_to_receive, m_heap_used); 00614 if (!m_has_hwfc && (m_pending_packet == NULL)) { 00615 // TODO: dropping data for this socket, we may want to close it 00616 } 00617 } 00618 } 00619 if ((m_pending_packet != NULL) && (len != 0)) { 00620 Packet *p = m_pending_packet; 00621 MBED_ASSERT(p->append(buf, len) == len); 00622 m_data_to_receive -= len; 00623 00624 if (m_data_to_receive == 0) { 00625 socket_t *s = m_pending_socket; 00626 00627 m_recv_state = RecvEnd; 00628 m_pending_packet = NULL; 00629 m_pending_socket = NULL; 00630 00631 socket_event_data_t data; 00632 data.data_received.packet = p; 00633 s->notify(EventDataReceived, data); 00634 } 00635 } 00636 break; 00637 } 00638 default: { 00639 cmd_resp_t rsp; 00640 if (this->parse_greeting(buf, len, fw_rev)) { 00641 if (m_greetings_cbk) { 00642 m_greetings_cbk(fw_rev); 00643 } 00644 } else if (strcmp(buf, "[OK]") == 0) { 00645 if (m_on_cmd_end) { 00646 Callback<void(cmd_resp_t)> cbk = m_on_cmd_end; 00647 m_on_cmd_end = NULL; 00648 cbk(CmdRspOk); 00649 } 00650 } else if (strncmp(buf, "AT", 2) == 0) { 00651 // echo enabled 00652 } else if (this->parse_error(buf, len, rsp)) { 00653 tr_debug("Error: %d", rsp); 00654 if (m_on_cmd_end) { 00655 Callback<void(cmd_resp_t)> cbk = m_on_cmd_end; 00656 m_on_cmd_end = NULL; 00657 cbk(rsp); 00658 } 00659 } else if (strcmp(buf, "[Link-Up Event]") == 0) { 00660 m_recv_state = LinkUpIP; 00661 } else if (strcmp(buf, "[Link-Down Event]") == 0) { 00662 if ((m_connection_status != NSAPI_STATUS_CONNECTING) || (m_cmd_ctx.connect.attempt == MBED_CONF_WIZFI310_CONNECT_MAX_ATTEMPT)) { 00663 this->set_connection_status(NSAPI_STATUS_DISCONNECTED); 00664 } 00665 // we may as well want to reset all sockets. 00666 } else if (strcmp(buf, "IF/SSID/IP-Addr/Gateway/MAC/TxPower(dBm)/RSSI(-dBm)") == 0) { 00667 MBED_ASSERT(m_active_action == ActionDoStatus); 00668 m_recv_state = Status; 00669 } else if (strcmp(buf, "Index/SSID/BSSID/RSSI(-dBm)/MaxDataRate(Mbps)/Security/RadioBand(GHz)/Channel") == 0) { 00670 MBED_ASSERT(m_active_action == ActionDoScan); 00671 m_recv_state = Scan; 00672 } else if (this->parse_connect(buf, len, id)) { 00673 socket_t *s = &m_sockets[id]; 00674 s->mutex.lock(); 00675 if (s->status != socket_t::StatusConnecting) { 00676 tr_warn("Unexpected connection on socket %d", id); 00677 } else if (m_active_action == ActionDoSOpen) { 00678 end_action(); 00679 } 00680 s->status = socket_t::StatusConnected; 00681 socket_event_data_t data; 00682 s->notify(EventConnected, data); 00683 s->mutex.unlock(); 00684 } else if (this->parse_disconnect(buf, len, id)) { 00685 socket_t *s = &m_sockets[id]; 00686 uint32_t act = m_active_action; 00687 00688 s->mutex.lock(); 00689 if (s->status == socket_t::StatusDisconnected) { 00690 tr_warn("Socket %d is already disconnected", id); 00691 } else { 00692 // tr_debug("act: %s s->status: %s", action2str((action_t)act), socket_t::status2str(s->status)); 00693 if ((act == ActionDoSOpen) && (s->status == socket_t::StatusConnecting)) { 00694 end_action(); 00695 } else { 00696 if ((act == ActionDoSClose) && (id == m_cmd_ctx.sclose.id)) { 00697 if (m_cmd_ctx.sclose.done) { 00698 end_action(); 00699 } else { 00700 m_cmd_ctx.sclose.id = -1; 00701 } 00702 } 00703 } 00704 } 00705 if (s->status != socket_t::StatusDisconnected) { 00706 s->status = socket_t::StatusDisconnected; 00707 socket_event_data_t data; 00708 s->notify(EventDisconnected, data); 00709 } 00710 // tr_debug("act: %s s->status: %s", action2str((action_t)m_active_action), socket_t::status2str(s->status)); 00711 s->mutex.unlock(); 00712 } else if (this->parse_send_rdy(buf, len, id, plen)) { 00713 MBED_ASSERT(m_active_action == ActionDoSSend); 00714 MBED_ASSERT(plen == m_cmd_ctx.ssend.amount); 00715 const char *data = (const char *)m_cmd_ctx.ssend.data; 00716 // tr_debug("Sending on %d: %s", id, print_buf(data, plen)); 00717 for (uint32_t i = 0; i < plen; i++) { 00718 m_serial.putc(*data); 00719 data++; 00720 } 00721 m_cmd_ctx.ssend.did_send = true; 00722 // send completion is signal by [OK]. 00723 } else if (this->parse_mac(buf, len, m_mac_buffer)) { 00724 // TODO: anything to do here ? 00725 } else if (this->parse_ip(buf, len, m_ip_buffer)) { 00726 // TODO: anything to do here ? 00727 } else { 00728 tr_warn("matches none: %.*s", (int)len, buf); 00729 } 00730 break; 00731 } 00732 } 00733 return false; 00734 } 00735 00736 void WizFi310::trace_cmd(const char *cmd, ...) 00737 { 00738 va_list args; 00739 va_start(args, cmd); 00740 if (MBED_TRACE_MAX_LEVEL >= TRACE_LEVEL_INFO) { 00741 char output[256]; 00742 int len = vsnprintf(output, 256, cmd, args); 00743 tr_info("%s|%s: sending: %.*s", recv_state2str(m_recv_state), action2str((action_t)m_active_action), len, output); 00744 (void)len; 00745 } 00746 va_end(args); 00747 } 00748 00749 void WizFi310::end_action() 00750 { 00751 m_active_action = ActionNone; 00752 } 00753 00754 // runs on the private event queue 00755 void WizFi310::do_reset() 00756 { 00757 m_serial.attach(NULL); 00758 m_attached = false; 00759 if (m_rst != NC) { 00760 m_nrst_pin = 0; 00761 // TODO: we may cause a framing error on the m_serial if we cut a transmition 00762 } 00763 00764 core_util_critical_section_enter(); 00765 if (m_rx_event_id != 0) { 00766 m_event_queue.cancel(m_rx_event_id); 00767 m_rx_event_id = 0; 00768 } 00769 core_util_critical_section_exit(); 00770 00771 m_isr_buf_len = 0; 00772 m_line_buf_len = 0; 00773 m_recv_state = Unknown; 00774 m_on_cmd_end = NULL; 00775 m_data_to_receive = 0; 00776 if (m_pending_packet != NULL) { 00777 delete m_pending_packet; 00778 m_pending_packet = NULL; 00779 } 00780 m_pending_socket = NULL; 00781 for (uint8_t i = 0; i < WIZFI310_SOCKET_COUNT; i++) { 00782 m_sockets[i].reset(); 00783 } 00784 MBED_ASSERT(m_heap_used == 0); // all packet must be freed prior to reset 00785 m_dhcp = true; 00786 if (m_rst == NC) { 00787 tr_warn("Using software reset may give unexpected results due to reception latency."); 00788 } else { 00789 // clear 00790 wait_ms(250); 00791 m_nrst_pin = 1; 00792 wait_ms(500); 00793 // flushes the serial port 00794 while (m_serial.getc() != -1); 00795 } 00796 00797 m_attached = true; 00798 m_serial.attach(Callback<void()>(this, &WizFi310::serial_isr)); 00799 00800 // this is a factory reset 00801 send_command("AT+MFDEF=FR\r"); 00802 00803 // TODO: setup a timeout ? 00804 m_greetings_cbk = Callback<void(const char[8])>(this, &WizFi310::do_echo_off); 00805 } 00806 00807 // runs on the event queue 00808 void WizFi310::do_echo_off(const char fw_rev[8]) 00809 { 00810 m_greetings_cbk = NULL; 00811 memcpy(m_firmware_rev, fw_rev, 8); 00812 m_recv_state = Ready; 00813 send_command("AT+MECHO=0\r"); 00814 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::do_setup_serial); 00815 } 00816 00817 // runs on the event queue 00818 void WizFi310::do_setup_serial(cmd_resp_t rsp) 00819 { 00820 if (rsp != CmdRspOk) { 00821 this->fatal_error("Failed to turn echo off"); 00822 return; 00823 } 00824 00825 #ifdef DEVICE_SERIAL_FC 00826 if (m_has_hwfc) { 00827 send_command("AT+USET=115200,N,8,1,HW\r"); 00828 } else 00829 #endif 00830 { 00831 // this shall have no effect as other wise we would be reaching this point. 00832 // we may in the future want to use a higher speed. 00833 send_command("AT+USET=115200,N,8,1,N\r"); 00834 } 00835 // m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::serial_setup_done); 00836 m_greetings_cbk = Callback<void(const char[8])>(this, &WizFi310::device_ready); 00837 } 00838 00839 /* 00840 void WizFi310::serial_setup_done(cmd_resp_t rsp) 00841 { 00842 if (rsp != CmdRspOk) { 00843 // signal end of connect 00844 this->fatal_error("Failed to setup the serial line"); 00845 return; 00846 } 00847 if (m_has_hwfc) { 00848 tr_debug("enabling flow control"); 00849 } 00850 m_greetings_cbk = Callback<void(const char[8])>(this, &WizFi310::device_ready); 00851 } 00852 */ 00853 00854 void WizFi310::device_ready(const char fw_rev[8]) 00855 { 00856 (void)fw_rev; // not used here. 00857 m_serial.set_flow_control(SerialBase::RTSCTS, m_rts, m_cts); 00858 m_greetings_cbk = NULL; 00859 00860 if (m_active_action == ActionDoConnect) { 00861 this->do_set_access_point(); 00862 } else if (m_active_action == ActionDoScan) { 00863 this->do_scan(); 00864 } else { 00865 this->fatal_error("Unexpected path to device_ready."); 00866 } 00867 } 00868 00869 void WizFi310::do_set_access_point() 00870 { 00871 send_command("AT+WSET=0,%s\r", m_cmd_ctx.connect.ap); 00872 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::do_set_password); 00873 } 00874 00875 // runs from the event queue 00876 void WizFi310::do_set_password(cmd_resp_t rsp) 00877 { 00878 if (rsp != CmdRspOk) { 00879 tr_error("Failed to set accesspoint name %s: %u", m_cmd_ctx.connect.ap, rsp); 00880 this->set_connection_status(NSAPI_STATUS_DISCONNECTED); 00881 this->end_action(); 00882 return; 00883 } 00884 00885 if (strcmp(m_cmd_ctx.connect.sec, "OPEN") == 0) { 00886 send_command("AT+WSEC=0,,12345678\r"); 00887 } else { 00888 send_command("AT+WSEC=0,,%s\r", m_cmd_ctx.connect.pw); 00889 } 00890 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::do_set_dhcp); 00891 } 00892 00893 // runs from the event queue 00894 void WizFi310::do_set_dhcp(cmd_resp_t rsp) 00895 { 00896 if (rsp != CmdRspOk) { 00897 tr_error("Failed to set password %s (%s): %u", m_cmd_ctx.connect.pw, m_cmd_ctx.connect.sec, rsp); 00898 this->set_connection_status(NSAPI_STATUS_DISCONNECTED); 00899 this->end_action(); 00900 return; 00901 } 00902 00903 if (m_dhcp) { 00904 send_command("AT+WNET=1\r"); 00905 } else { 00906 // we need to have a way to set these 00907 send_command("AT+WNET=0,%s,%s,%s\r", m_ip_buffer, m_netmask_buffer, m_gateway_buffer); 00908 } 00909 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::do_join); 00910 } 00911 00912 // runs from the event queue 00913 void WizFi310::do_join(cmd_resp_t rsp) 00914 { 00915 if (rsp != CmdRspOk) { 00916 tr_error("Failed configure dhcp: %s (%s,%s,%s)", 00917 m_dhcp ? "enabled" : "disabled", m_ip_buffer, m_netmask_buffer, m_gateway_buffer); 00918 this->set_connection_status(NSAPI_STATUS_DISCONNECTED); 00919 this->end_action(); 00920 return; 00921 } 00922 send_command("AT+WJOIN\r"); 00923 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::join_done); 00924 } 00925 00926 // runs from the event queue 00927 void WizFi310::join_done(cmd_resp_t rsp) 00928 { 00929 if (m_connection_status == NSAPI_STATUS_GLOBAL_UP) { 00930 this->end_action(); 00931 } else if (m_cmd_ctx.connect.attempt < MBED_CONF_WIZFI310_CONNECT_MAX_ATTEMPT) { 00932 m_cmd_ctx.connect.attempt += 1; 00933 this->do_join(CmdRspOk); 00934 } else { 00935 this->end_action(); 00936 } 00937 } 00938 00939 void WizFi310::do_scan() 00940 { 00941 send_command("AT+WSCAN\r"); 00942 } 00943 00944 // runs from the event queue 00945 void WizFi310::leave_done(cmd_resp_t rsp) 00946 { 00947 this->end_action(); 00948 } 00949 00950 const char *WizFi310::get_ip_address() 00951 { 00952 return m_ip_buffer; 00953 } 00954 00955 void WizFi310::sopen_done(cmd_resp_t rsp) 00956 { 00957 socket_t *s = m_cmd_ctx.sopen.s; 00958 00959 if (rsp != CmdRspOk) { 00960 MBED_ASSERT(m_active_action != ActionDoSSend); 00961 end_action(); 00962 socket_event_data_t data; 00963 s->notify(EventDisconnected, data); 00964 } 00965 } 00966 00967 void WizFi310::ssend_done(cmd_resp_t rsp) 00968 { 00969 socket_event_data_t data; 00970 socket_t *s = m_cmd_ctx.ssend.s; 00971 if (rsp == CmdRspErrorInvalidInput) { 00972 data.data_sent.amount_or_error = NSAPI_ERROR_PARAMETER; 00973 } else if (rsp != CmdRspOk) { 00974 data.data_sent.amount_or_error = NSAPI_ERROR_DEVICE_ERROR; 00975 } else { 00976 MBED_ASSERT(m_cmd_ctx.ssend.did_send); 00977 uint32_t sent = m_cmd_ctx.ssend.amount; 00978 this->end_action(); 00979 00980 data.data_sent.amount_or_error = sent; 00981 } 00982 s->notify(EventDataSent, data); 00983 } 00984 00985 void WizFi310::do_sclose(int id) 00986 { 00987 uint32_t expected = ActionNone; 00988 socket_t *s = &m_sockets[id]; 00989 tr_debug("::do_close(%d): %s", id, socket_t::status2str(s->status)); 00990 if (s->status == socket_t::StatusDisconnected) { 00991 return; 00992 } 00993 if (!core_util_atomic_cas_u32(&m_active_action, &expected, ActionDoSClose)) { 00994 m_event_queue.call(this, &WizFi310::do_sclose, id); 00995 return; 00996 } 00997 m_cmd_ctx.sclose.id = id; 00998 m_cmd_ctx.sclose.done = false; 00999 send_command("AT+SMGMT=%d\r", id); 01000 m_on_cmd_end = Callback<void(cmd_resp_t)>(this, &WizFi310::sclose_done); 01001 } 01002 01003 void WizFi310::sclose_done(cmd_resp_t rsp) 01004 { 01005 int id = m_cmd_ctx.sclose.id; 01006 if (rsp != CmdRspOk) { 01007 MBED_ASSERT(m_active_action != ActionDoSSend); 01008 end_action(); 01009 m_event_queue.call(this, &WizFi310::do_sclose, id); 01010 } else if (id < 0) { 01011 MBED_ASSERT(m_active_action != ActionDoSSend); 01012 end_action(); 01013 } else { 01014 m_cmd_ctx.sclose.done = true; 01015 } 01016 } 01017 01018 void WizFi310::socket_t::reset() 01019 { 01020 this->mutex.lock(); 01021 if (this->status != socket_t::StatusDisconnected) { 01022 this->status = socket_t::StatusDisconnected; 01023 socket_event_data_t data; 01024 this->notify(EventDisconnected, data); 01025 } 01026 this->mutex.unlock(); 01027 } 01028 01029 // must be called when the mutex is locked 01030 void WizFi310::socket_t::notify(socket_event_t evt, socket_event_data_t &data) 01031 { 01032 this->mutex.lock(); 01033 if (this->cbk) { 01034 this->cbk(this->data, evt, data); 01035 } else if (evt == EventDataReceived) { 01036 // nobody will take ownership of this packet. 01037 tr_warning("Receiving %lu bytes on a closed socket.", data.data_received.packet->len()); 01038 delete data.data_received.packet; 01039 } 01040 this->mutex.unlock(); 01041 } 01042
Generated on Mon Aug 29 2022 19:53:42 by
