summaryrefslogtreecommitdiffstatshomepage
path: root/extmod/modlwip.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-08-13 21:24:32 +1000
committerDamien George <damien.p.george@gmail.com>2017-08-13 21:24:32 +1000
commitb084ab966e2d4d18c9b2be8317541313f0e2586f (patch)
treeee073405e02d4d23c1bdb1e85b0c5a9842e0010b /extmod/modlwip.c
parent72912c753a31301efb7d6b2f35dd1e3e64b98cd4 (diff)
parent2c2fc070ecca654b0e9a80e1d9a342d46c6f0cdb (diff)
downloadmicropython-b084ab966e2d4d18c9b2be8317541313f0e2586f.tar.gz
micropython-b084ab966e2d4d18c9b2be8317541313f0e2586f.zip
Merge tag 'v1.8' into parse-bytecode
First general release of ESP8266 port, and support for frozen bytecode This release marks the first general release of official ESP8266 support within the MicroPython code base. The ESP8266 port has many improvements and additions, including: websocket and webrepl modules, deep-sleep mode, reading on UART, enhanced I2C support, enhanced network configuration, full sequence of start-up scripts (built-in _boot.py, boot.py and main.py), improved filesystem support with automatic flash-size detection as well as documentation and a tutorial. Known issues with ESP8266 port are: - Basic SSL support is available but it works only with relatively short data lengths (a few kilobytes). - WebREPL over SSL is not supported. - Only 5 or so WebREPL sessions in succession can be started (including file transfer sessions), after that the board requires a hard reset. - File transfer over WebREPL has issues with large files (above a few tens of kilobytes). - By design, only one concurrent WebREPL connection is supported. - Soft reset doesn't reset the network stack. In addition to ESP8266 support, this release brings frozen bytecode which allows to compile bytecode offline and link it into the firmware, completely eliminating the need for compilation (and the associated RAM usage) at runtime. Basic async/await syntax is now supported, and qstrs are now auto-generated in the build system. A detailed list of changes is given below. README: - explicitly point to required dependencies section - promote "docs" and "tests" to "major components" - mention support "async" keyword from Python 3.5 ACKNOWLEDGEMENTS: - add list of 842 backers from the ESP8266 campaign py core: - modbuiltins: add comment about setting "_" special var - add async/await/async for/async with syntax - fix constant folding and inline-asm to work with new async grammar - emitglue: move typedef of mp_raw_code_t from .c to .h file - emitglue: make mp_raw_code_t* arguments constant pointers - makeqstrdata: factor out some code to functions that can be reused - add ability to have frozen persistent bytecode from .mpy files - makeqstrdata: add more names for escaped chars and esc non-printable - simplify "and" action within parser by making ident-rules explicit - makeqstrdata: fix rendering of qstrs that have non-printable ASCII - makeqstrdata: add special case to handle \n qstr - declare help, input, open builtins in core - map: change hash-table allocation policy to be less aggressive - makeqstrdefs: add script to automate extraction of qstr from sources - frozenmod: pass the source name of the frozen module to the lexer - rework QSTR extraction to work in simple and obvious way - divide "split" and "cat" phases of qstr extraction for better efficiency - fix bug passing a string as a keyword arg in a dict - move call_function_*_protected() functions to py/ for reuse - makeqstrdefs.py: windows compatibility - obj.h: when constructing a small-int cast to mp_uint_t for bit-shift - emitnative: use MP_OBJ_NEW_SMALL_INT instead of manual bit shifting - vm: "yield from" didn't handle MP_OBJ_STOP_ITERATION optimization - modio: rename module name to "uio" for consistency with other modules - modcollections: rename module name have "u" prefix for consistency extmod: - add initial framebuf module - add generic machine.I2C class, with bit-bang I2C - machine_i2c: fix I2C reading by sending ack/nack at end of byte - machine_i2c: implement I2C memory reading/writing - moduos_dupterm: don't swallow exceptions in dupterm's read()/write() - modlwip: lwip_tcp_receive(): Properly handle EOF for non-blocking sock - modlwip: more debug messages for various edge conditions - fsusermount: in mount/mkfs, deregister VFS object on error - modlwip: lwip_tcp_send(): full error handling - modlwip: lwip_tcp_receive(): full error handling - modlwip: add ability to run callback on "recv" and "accept" events - machine_i2c: allow mp_hal_pin_obj_t to be any type, not a ptr - modlwip: protect recv/accept Python callback against exceptions - modlwip: workaround esp8266 sendto issue where 1 is returned - modlwip: add print_pcbs() debug function - modwebsocket: handle CLOSE control frame - modussl: throw Python exceptions in case of errors - modussl: support server-side SSL sockets - modussl: SSL_OK from ssl_read() means "no user data so far" - modwebrepl: module to handle WebREPL protocol - modwebrepl: initial implementation of "get file" operation - modwebrepl: keep reading data when there's something to read - modwebrepl: GET_FILE: Send length-prefix chunk with one write() - modwebrepl: add rate-limiting workaround for broken network drivers - modwebrepl: set debugging by default to off - modwebrepl: add support for password - modlwip: implement sendall() method for TCP sockets - fix typo of macro that detects if float is enabled lib: - utils/printf: rework overriding printer of DEBUG_printf() - utils/pyexec: condition-out GC calls from pyexec - utils/pyhelp: extract implementation of help(obj) to a library function - axtls: update to the latest upstream, fix reported MacOSX build issue drivers: - add SSD1306 OLED driver, with I2C and SPI interfaces tools: - mpy-tool.py: new tool to work with .mpy files; currently it can freeze them - mpy-tool.py: add support for Python 2.7 tests: - add 6 tests for async await/for/with - add .exp files for async tests, so they can run with Python 3.4 - fix dict1.py so it doesn't rely on the order of dict elems - extmod: move split-on-empty-match tests to a separate test file - add testcase for yielding from a stopped generator - run-bench-tests: process tests in alphabetical order - update for _io/_collections module having been renamed minimal port: - add example of frozen persistent bytecode (.mpy file) - disable async/await syntax unix port: - build with MICROPY_PY_UHASHLIB_SHA1 if already building with axTLS - make sure build dir exists before accessing it for freezing upip - Makefile: make install more compatible (BSD, etc.) windows port: - msvc: implement automatic qstr generation using makeqstrdefs stmhal port: - implement basic C-level pin HAL - use new generic I2C object in machine module - enable framebuf module - properly handle RTS/CTS flow control for buf/unbuf transfers - add Makefile option FROZEN_MPY_DIR to support frozen bytecode - for frozen bytecode generation, add dependency of qstr file - l4: add CMSIS files to support STM32L476 - l4: add basic STM32L4xx HAL files - l4: adapt UART HAL to avoid 64-bit integer division - update HALCOMMITS due to change to hal - l4: add board definition files for STM32L476DISC - l4: add line to Makefile for building L4 series - l4: modify adc.c to add support for STM32L4 series - l4: modify uart.c to support L4 MCU - l4: modify usbd_conf.c to support L4 MCU - l4: modify rtc.c to support L4 MCU - l4: modify timer.c to support L4 MCU - fix machine.unique_id() function to work for all MCUs - l4: modify mphalport to support L4 MCU - l4: modify flash.c and storage.c to support L4 MCU - l4: add support for external interrupts/events - accel: raise an exception if the accel couldn't be initialised - use pyhelp_print_obj function - change i2c.scan() method to scan addresses 0x08-0x77 - fix typo of macro that detects if float is enabled cc3200 port: - use pyhelp_print_obj function - change i2c.scan() method to scan addresses 0x08-0x77 - disable async/await syntax esp8266 port: - enable websocket module - modnetwork: .config(): Check interface whose config is requested - modnetwork: .config(): Add "authmode" param - modnetwork: .config(): Add "password" param (W/O) - add Python modules for initial configuration - scripts/inisetup.py: set WPA/WPA2 AP mode with a predefined password - protect modpyb.h header file from multiple inclusions - implement basic C-level pin HAL - switch from using custom I2C driver to generic extmod one - enable framebuf module - in callback helpers, pop nlr_buf on successful call - esp_mphal: don't swallow exceptions in dupterm's read()/write() - esp_mphal: call_dupterm_read(): Fix order of deactivating on EOF - remove pin_id field from C pin object - add dummy entries for non-existing pins to simplify pin logic - add hard IRQ callbacks for pin change on GPIO0-15 - separate 1-wire timing funcs from Python module to save iRAM - switch integer arith routines to BootROM - scripts/port_diag.py: module to collect diagnostic info - enable input() builtin - scripts/_boot: mount block device on "" instead of "/" - moduos: add uos.mkdir function - modmachine: add reset_cause() function - adapt port to use new auto-qstr generation - moduos: add dupterm_notify() function - esp_mphal: protect dupterm_task_handler() from recursive exec - README.md: update feature list for current state of affairs - modesp: allow esp.deepsleep to take 2nd arg for RF wake opt - scripts/flashbdev: use all available space in 1MB FlashROM for FS - modesp: add flash_size() function - scripts: don't try to create filesystem on 512KB devices or less - modnetwork: .config(): Add "channel" param - scripts/flashbdev: disable debug output/checks - scripts/_boot: print notice when initial setup is executed - scripts/flashbdev: correct bootloader flash size to match real size - modnetwork: .config(): Add "hidden ESSID" param - implement basic deep-sleep capabilities - add uart_rx_wait and uart_rx_char functions - implement UART.read functionality - uart: remove obsolete UART rx buffering code - esp_mphal: remove mp_hal_feed_watchdog - convert mp_hal_pin_obj_t from pin ptr to simple integer - allow GPIO16 to be used as a pin in the uPy pin HAL - change software SPI driver to use general pin HAL - scripts/websocket_helper: module encapsulating handshake sequences - scripts/websocket_helper: disable debug output - scripts/webrepl: webREPL based on C-level websocket object - scripts/webrepl: convert to persistent daemon - scripts/webrepl: don't start on import - scripts/webrepl: allow to override port - scripts/webrepl: print connection address - scripts/webrepl: print client address for incoming connections - scripts/flashbdev: use all available Flash for filesystem - scripts/webrepl: add "ws://" to "daemon started at" message - Makefile: add target to build axTLS - esp8266.ld: put axTLS to FlashROM - Makefile: override abort() when building axtls - axtls_helpers: helper/wrapper functions for axTLS - tests/onewire.py: don't run test on import - Makefile: support linking with axTLS built from source - Makefile: enable "ussl" module; axTLS should be built first using "make axtls" - move pyb.info() function to esp module and remove pyb module - move onewire.py, neopixel.py drivers from tests/ to scripts/ - scripts/onewire.py: simplify and improve 1-wire driver - scripts/neopixel.py: remove test function from neopixel driver - set suitable values for axtls's RT_MAX_PLAIN_LENGTH & RT_EXTRA - README: add recently required step of 'make axtls' - modnetwork: make WLAN.ifconfig() read/write - help: implement help() builtin - help: add cheatsheet for basic WiFi configuration - enable WebREPL file transfer rate limiting - enable webrepl module - scripts: move all of initial setup to inisetup module - scripts/inisetup: create default boot.py in filesystem - scripts/webrepl: connection ack prompt is now printed by modwebrepl - scripts/webrepl: switch to using _webrepl object wrapper - scripts/webrepl: add "first connection" mode to setup password - README: mention WebREPL - Makefile: be sure to pass cross-compiling AR when building axtls - scripts/webrepl_setup: reject too short passwords - change platform name from ESP8266 to esp8266 - modnetwork: remove deprecated wifi_mode() - esp_mphal: add ets_esf_free_bufs(), etc. functions - modesp: add esf_free_bufs() debugging function - modesp: add malloc() and free() functions - scripts/inisetup: enable WebREPL auto-start on boot - modnetwork: remove .mac() method, move to .config("mac") - scripts/inisetup: update for nic.mac() method being gone - scripts/neopixel.py: swap red and green in pixel accessor - modpybpin: use enum+array instead of struct for parsing args - modpybpin: use None instead of PULL_NONE for no-pull config - modpybpin: make pin.irq() methods take keyword args - tutorial: mention that esptool is available via pip - scripts/ntptime: add simple NTP client docs: - esp: enumerate flash access functions - machine: start to update for esp8266 port - speed_python: clarify/generalize "Buffers" subsection - speed_python: generalize "Floating point" subsection - speed_python: add many more details on memoryviews - machine: reset_cause() has been implemented for esp8266 - topindex.html: esp8266: Enable quickref/general on the main page - esp8266/general: start "General information" for esp8266 - esp8266: add info about using deep-sleep mode to quickref - esp8266/tutorial: add tutorial placeholder page - ustruct: there's no complete "struct" module, only "ustruct" subset - esp8266: include usocket module reference - library/usocket: add link to CPython's socket module - usocket: socket-specific exceptions are for WiPy only - usocket: socket.IPPROTO_SEC is WiPy-specific - usocket: describe address format once at the beginning - network: esp8266: scan(): add note that bssid is bytes object - library: group MicroPython-specific modules under separate heading - library/index: move WiPy "micro-libraries" under corresponding heading - library/index: esp8266 has the same set of stdlibs as pyboard/unix - module "time" is actually "utime" - library/index: make single section for "micro-ified" modules - library/index: order sections from the most to least standard modules - Makefile: default BUILDDIR based on MICROPY_PORT - library: "os" module is actually "uos" - fix uos and utime heading underlines to be the correct length - library/utime: add more time functions for unix and esp8266 ports - utime: describe time() peculiarities in MicroPython - utime: describe sleep() peculiarities in MicroPython - library: consistently use admonitions for CPython differences - ubinascii: clean up grammar - network: esp8266: Add wlan.ifconfig() method - network: esp8266: Describe wlan.config() method - make the short port names in the port/version sidebar lowercase - esp8266: update quickref to reflect changes to 1-wire and NeoPixel - library/utime: elaborate on epochs and calendar time maintenance - esp8266/quickref: add info about WebREPL - ustruct: document pack_into(), unpack_from() - sys: document sys.modules - ustruct: fix argument formatting - sys: remove port-specific details from description of stdin/out/err - sys: clarify description of sys.exit() - sys: clean up print_exception() description - sys: describe sys.implementation - sys: describe sys.maxsize - sys: describe sys.platform is port-neutral manner - add _collections module reference - add _io module reference - _io and _collections were renamed to have standard "u" prefix - library/machine.I2C: update to reflect ESP8266 implementation - esp8266/general: webREPL is described in quickref for now - esp8266/general: add more points to "Multitude of boards" section - esp8266/general: fix list formatting - esp8266/general: add techspec section - esp8266/general: add "Boot process" section - esp8266_contents: reference general and tutorial docs - network: esp8266: MAC address is set via .config() method - esp8266: add ESP8266 tutorial - machine: generalize docs from just WiPy to other ports - machine: move WiPy-specific hardware details to its general reference - machine: more generic description of sleep's, WiPy details to its genref - machine: idle() description generalization - library/machine.Pin: update pin docs to reflect ESP8266 support - esp8266/tutorial: update pins tutorial to reflect changes in API examples: - http_server_ssl.py: add HTTPS server example
Diffstat (limited to 'extmod/modlwip.c')
-rw-r--r--extmod/modlwip.c130
1 files changed, 120 insertions, 10 deletions
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index 1ebcd8923c..090e1005a8 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -43,6 +43,13 @@
#include "lwip/udp.h"
//#include "lwip/raw.h"
#include "lwip/dns.h"
+#include "lwip/tcp_impl.h"
+
+#if 0 // print debugging info
+#define DEBUG_printf DEBUG_printf
+#else // don't print debugging info
+#define DEBUG_printf(...) (void)0
+#endif
// For compatibilily with older lwIP versions.
#ifndef ip_set_option
@@ -228,6 +235,7 @@ typedef struct _lwip_socket_obj_t {
struct pbuf *pbuf;
struct tcp_pcb *connection;
} incoming;
+ mp_obj_t callback;
byte peer[4];
mp_uint_t peer_port;
mp_uint_t timeout;
@@ -255,6 +263,12 @@ static inline void poll_sockets(void) {
/*******************************************************************************/
// Callback functions for the lwIP raw API.
+static inline void exec_user_callback(lwip_socket_obj_t *socket) {
+ if (socket->callback != MP_OBJ_NULL) {
+ mp_call_function_1_protected(socket->callback, socket);
+ }
+}
+
// Callback for incoming UDP packets. We simply stash the packet and the source address,
// in case we need it for recvfrom.
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
@@ -303,11 +317,13 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
tcp_recv(newpcb, _lwip_tcp_recv_unaccepted);
if (socket->incoming.connection != NULL) {
+ DEBUG_printf("_lwip_tcp_accept: Tried to queue >1 pcb waiting for accept\n");
// We need to handle this better. This single-level structure makes the
// backlog setting kind of pointless. FIXME
return ERR_BUF;
} else {
socket->incoming.connection = newpcb;
+ exec_user_callback(socket);
return ERR_OK;
}
}
@@ -318,13 +334,18 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
if (p == NULL) {
// Other side has closed connection.
+ DEBUG_printf("_lwip_tcp_recv[%p]: other side closed connection\n", socket);
socket->state = STATE_PEER_CLOSED;
+ exec_user_callback(socket);
return ERR_OK;
} else if (socket->incoming.pbuf != NULL) {
// No room in the inn, let LWIP know it's still responsible for delivery later
return ERR_BUF;
}
socket->incoming.pbuf = p;
+
+ exec_user_callback(socket);
+
return ERR_OK;
}
@@ -359,7 +380,10 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
pbuf_free(p);
- if (err != ERR_OK) {
+ // udp_sendto can return 1 on occasion for ESP8266 port. It's not known why
+ // but it seems that the send actually goes through without error in this case.
+ // So we treat such cases as a success until further investigation.
+ if (err != ERR_OK && err != 1) {
*_errno = error_lookup_table[-err];
return -1;
}
@@ -401,15 +425,27 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
return (mp_uint_t) result;
}
+// For use in stream virtual methods
+#define STREAM_ERROR_CHECK(socket) \
+ if (socket->state < 0) { \
+ *_errno = error_lookup_table[-socket->state]; \
+ return MP_STREAM_ERROR; \
+ } \
+ assert(socket->pcb.tcp);
+
+
// Helper function for send/sendto to handle TCP packets
STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
+ // Check for any pending errors
+ STREAM_ERROR_CHECK(socket);
+
u16_t available = tcp_sndbuf(socket->pcb.tcp);
if (available == 0) {
// Non-blocking socket
if (socket->timeout == 0) {
*_errno = EAGAIN;
- return -1;
+ return MP_STREAM_ERROR;
}
mp_uint_t start = mp_hal_ticks_ms();
@@ -422,15 +458,13 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
while (socket->state >= STATE_CONNECTED && (available = tcp_sndbuf(socket->pcb.tcp)) < 16) {
if (socket->timeout != -1 && mp_hal_ticks_ms() - start > socket->timeout) {
*_errno = ETIMEDOUT;
- return -1;
+ return MP_STREAM_ERROR;
}
poll_sockets();
}
- if (socket->state < 0) {
- *_errno = error_lookup_table[-socket->state];
- return -1;
- }
+ // While we waited, something could happen
+ STREAM_ERROR_CHECK(socket);
}
u16_t write_len = MIN(available, len);
@@ -439,7 +473,7 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
if (err != ERR_OK) {
*_errno = error_lookup_table[-err];
- return -1;
+ return MP_STREAM_ERROR;
}
return write_len;
@@ -447,10 +481,16 @@ STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
// Helper function for recv/recvfrom to handle TCP packets
STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
+ // Check for any pending errors
+ STREAM_ERROR_CHECK(socket);
+
if (socket->incoming.pbuf == NULL) {
// Non-blocking socket
if (socket->timeout == 0) {
+ if (socket->state == STATE_PEER_CLOSED) {
+ return 0;
+ }
*_errno = EAGAIN;
return -1;
}
@@ -463,6 +503,7 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
poll_sockets();
}
+
if (socket->state == STATE_PEER_CLOSED) {
if (socket->incoming.pbuf == NULL) {
// socket closed and no data left in buffer
@@ -475,6 +516,8 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
}
}
+ assert(socket->pcb.tcp != NULL);
+
struct pbuf *p = socket->incoming.pbuf;
if (socket->leftover_count == 0) {
@@ -515,6 +558,7 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args
socket->base.type = (mp_obj_t)&lwip_socket_type;
socket->domain = MOD_NETWORK_AF_INET;
socket->type = MOD_NETWORK_SOCK_STREAM;
+ socket->callback = MP_OBJ_NULL;
if (n_args >= 1) {
socket->domain = mp_obj_get_int(args[0]);
if (n_args >= 2) {
@@ -569,6 +613,7 @@ STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) {
socket_is_listener = true;
}
if (tcp_close(socket->pcb.tcp) != ERR_OK) {
+ DEBUG_printf("lwip_close: had to call tcp_abort()\n");
tcp_abort(socket->pcb.tcp);
}
break;
@@ -689,6 +734,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
socket2->timeout = socket->timeout;
socket2->state = STATE_CONNECTED;
socket2->leftover_count = 0;
+ socket2->callback = MP_OBJ_NULL;
tcp_arg(socket2->pcb.tcp, (void*)socket2);
tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);
@@ -918,13 +964,55 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_recvfrom_obj, lwip_socket_recvfrom);
+STATIC mp_obj_t lwip_socket_sendall(mp_obj_t self_in, mp_obj_t buf_in) {
+ lwip_socket_obj_t *socket = self_in;
+ lwip_socket_check_connected(socket);
+
+ int _errno;
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+
+ mp_uint_t ret = 0;
+ switch (socket->type) {
+ case MOD_NETWORK_SOCK_STREAM: {
+ if (socket->timeout == 0) {
+ // Behavior of sendall() for non-blocking sockets isn't explicitly specified.
+ // But it's specified that "On error, an exception is raised, there is no
+ // way to determine how much data, if any, was successfully sent." Then, the
+ // most useful behavior is: check whether we will be able to send all of input
+ // data without EAGAIN, and if won't be, raise it without sending any.
+ if (bufinfo.len > tcp_sndbuf(socket->pcb.tcp)) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EAGAIN)));
+ }
+ }
+ // TODO: In CPython3.5, socket timeout should apply to the
+ // entire sendall() operation, not to individual send() chunks.
+ while (bufinfo.len != 0) {
+ ret = lwip_tcp_send(socket, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret == -1) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+ bufinfo.len -= ret;
+ bufinfo.buf = (char*)bufinfo.buf + ret;
+ }
+ break;
+ }
+ case MOD_NETWORK_SOCK_DGRAM:
+ mp_not_implemented("");
+ break;
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_sendall_obj, lwip_socket_sendall);
+
STATIC mp_obj_t lwip_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
lwip_socket_obj_t *socket = self_in;
mp_uint_t timeout;
if (timeout_in == mp_const_none) {
timeout = -1;
} else {
- #if MICROPY_PY_BUILTIN_FLOAT
+ #if MICROPY_PY_BUILTINS_FLOAT
timeout = 1000 * mp_obj_get_float(timeout_in);
#else
timeout = 1000 * mp_obj_get_int(timeout_in);
@@ -950,8 +1038,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblo
STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; // always 4
lwip_socket_obj_t *socket = args[0];
+
+ int opt = mp_obj_get_int(args[2]);
+ if (opt == 20) {
+ if (args[3] == mp_const_none) {
+ socket->callback = MP_OBJ_NULL;
+ } else {
+ socket->callback = args[3];
+ }
+ return mp_const_none;
+ }
+
+ // Integer options
mp_int_t val = mp_obj_get_int(args[3]);
- switch (mp_obj_get_int(args[2])) {
+ switch (opt) {
case SOF_REUSEADDR:
// Options are common for UDP and TCP pcb's.
if (val) {
@@ -1010,6 +1110,7 @@ STATIC const mp_map_elem_t lwip_socket_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&lwip_socket_recv_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&lwip_socket_sendto_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&lwip_socket_recvfrom_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_sendall), (mp_obj_t)&lwip_socket_sendall_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&lwip_socket_settimeout_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&lwip_socket_setblocking_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&lwip_socket_setsockopt_obj },
@@ -1143,6 +1244,14 @@ STATIC mp_obj_t lwip_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_getaddrinfo_obj, lwip_getaddrinfo);
+// Debug functions
+
+STATIC mp_obj_t lwip_print_pcbs() {
+ tcp_debug_print_pcbs();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(lwip_print_pcbs_obj, lwip_print_pcbs);
+
#ifdef MICROPY_PY_LWIP
STATIC const mp_map_elem_t mp_module_lwip_globals_table[] = {
@@ -1150,6 +1259,7 @@ STATIC const mp_map_elem_t mp_module_lwip_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_reset), (mp_obj_t)&mod_lwip_reset_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_callback), (mp_obj_t)&mod_lwip_callback_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&lwip_getaddrinfo_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_print_pcbs), (mp_obj_t)&lwip_print_pcbs_obj },
// objects
{ MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&lwip_socket_type },
#ifdef MICROPY_PY_LWIP_SLIP