From 9e00ac89d5062414b618b3e961acda04ddc8a30d Mon Sep 17 00:00:00 2001 From: Josef Gajdusek Date: Sat, 2 May 2015 21:24:25 +0200 Subject: [PATCH] esp8266: Add esp.socket class, with ESP-style socket functionality. * UDP currently not supported * As there is no way (that I know of) the espconn_regist_connectcb() callback can recognize on which socket has the connection arrived, only one listening function at a time is supported --- esp8266/Makefile | 3 + esp8266/modesp.c | 448 +++++++++++++++++++++++++++++++++++++++-- esp8266/mpconfigport.h | 6 +- esp8266/qstrdefsport.h | 17 ++ esp8266/utils.c | 50 +++++ esp8266/utils.h | 29 +++ 6 files changed, 536 insertions(+), 17 deletions(-) create mode 100644 esp8266/utils.c create mode 100644 esp8266/utils.h diff --git a/esp8266/Makefile b/esp8266/Makefile index 1909e0d76e..389e86edf9 100644 --- a/esp8266/Makefile +++ b/esp8266/Makefile @@ -14,6 +14,7 @@ INC = -I. INC += -I.. INC += -I../stmhal INC += -I../lib/mp-readline +INC += -I../lib/netutils INC += -I$(BUILD) INC += -I$(ESP_SDK)/include @@ -49,6 +50,7 @@ SRC_C = \ modpyb.c \ modpybpin.c \ modesp.c \ + utils.c \ STM_SRC_C = $(addprefix stmhal/,\ printf.c \ @@ -59,6 +61,7 @@ STM_SRC_C = $(addprefix stmhal/,\ LIB_SRC_C = $(addprefix lib/,\ libc/string0.c \ mp-readline/readline.c \ + netutils/netutils.c \ ) SRC_S = \ diff --git a/esp8266/modesp.c b/esp8266/modesp.c index bc1e6f9c75..f5baadcbf7 100644 --- a/esp8266/modesp.c +++ b/esp8266/modesp.c @@ -33,31 +33,445 @@ #include "py/gc.h" #include "py/runtime.h" #include MICROPY_HAL_H +#include "netutils.h" #include "queue.h" #include "user_interface.h" +#include "espconn.h" +#include "utils.h" + +STATIC const mp_obj_type_t esp_socket_type; + +typedef struct _esp_socket_obj_t { + mp_obj_base_t base; + struct espconn *espconn; + + mp_obj_t cb_connect; + mp_obj_t cb_recv; + mp_obj_t cb_disconnect; + + uint8_t *recvbuf; + mp_uint_t recvbuf_len; + + bool fromserver; + + mp_obj_list_t *connlist; +} esp_socket_obj_t; + +// Due to the onconnect callback not being able to recognize the parent esp_socket, +// we can have only one esp_socket listening at a time +// This should be solvable by some PIC hacking +STATIC esp_socket_obj_t *esp_socket_listening; + +STATIC mp_obj_t esp_socket_make_new_base() { + esp_socket_obj_t *s = m_new_obj_with_finaliser(esp_socket_obj_t); + s->recvbuf = NULL; + s->base.type = (mp_obj_t)&esp_socket_type; + s->cb_connect = mp_const_none; + s->cb_recv = mp_const_none; + s->cb_disconnect = mp_const_none; + s->fromserver = false; + return s; +} + +// constructor esp_socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None) +// Arguments ignored as we do not support UDP (yet) +STATIC mp_obj_t esp_socket_make_new(mp_obj_t type_in, mp_uint_t n_args, + mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + esp_socket_obj_t *s = esp_socket_make_new_base(); + s->espconn = m_new_obj(struct espconn); + espconn_create(s->espconn); + + s->espconn->reverse = s; + // TODO: UDP Support + s->espconn->type = ESPCONN_TCP; + s->espconn->state = ESPCONN_NONE; + + s->espconn->proto.tcp = m_new_obj(esp_tcp); + + return s; +} + +// method socket.close() +STATIC mp_obj_t esp_socket_close(mp_obj_t self_in) { + esp_socket_obj_t *s = self_in; + + if (esp_socket_listening == s) { + esp_socket_listening = NULL; + } + + if (s->espconn->state != ESPCONN_NONE && s->espconn->state != ESPCONN_CLOSE) { + espconn_disconnect(s->espconn); + } + + if (s->connlist != NULL) { + mp_obj_list_set_len(s->connlist, 0); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_socket_close_obj, esp_socket_close); + +// method socket.__del__() +STATIC mp_obj_t esp_socket___del__(mp_obj_t self_in) { + esp_socket_obj_t *s = self_in; + + esp_socket_close(self_in); + + if (s->fromserver) { + espconn_delete(s->espconn); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_socket___del___obj, esp_socket___del__); + +// method socket.bind(address) +STATIC mp_obj_t esp_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + esp_socket_obj_t *s = self_in; + + mp_uint_t port = netutils_parse_inet_addr(addr_in, + s->espconn->proto.tcp->remote_ip, NETUTILS_BIG); + s->espconn->proto.tcp->local_port = port; + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_bind_obj, esp_socket_bind); + +STATIC void esp_socket_recv_callback(void *arg, char *pdata, unsigned short len) { + struct espconn *conn = arg; + esp_socket_obj_t *s = conn->reverse; + + if (s->cb_recv != mp_const_none) { + call_function_2_protected(s->cb_recv, s, mp_obj_new_bytes((byte *)pdata, len)); + } else { + if (s->recvbuf == NULL) { + s->recvbuf = gc_alloc(len, false); + s->recvbuf_len = len; + if (s->recvbuf != NULL) { + memcpy(s->recvbuf, pdata, len); + } + } else { + s->recvbuf = gc_realloc(s->recvbuf, s->recvbuf_len + len); + if (s->recvbuf != NULL) { + memcpy(&s->recvbuf[s->recvbuf_len], pdata, len); + s->recvbuf_len += len; + } + } + if (s->recvbuf == NULL) { + esp_socket_close(s); + return; + } + } +} + +STATIC void esp_socket_sent_callback(void *arg) { +} + +STATIC void esp_socket_disconnect_callback(void *arg) { + struct espconn *conn = arg; + esp_socket_obj_t *s = conn->reverse; + + if (s->cb_disconnect != mp_const_none) { + call_function_1_protected(s->cb_disconnect, s); + } + + esp_socket_close(s); +} + +STATIC void esp_socket_connect_callback_server(void *arg) { + struct espconn *conn = arg; + + esp_socket_obj_t *s = esp_socket_make_new_base(); + s->espconn = conn; + s->fromserver = true; + conn->reverse = s; + + espconn_regist_recvcb(conn, esp_socket_recv_callback); + espconn_regist_sentcb(conn, esp_socket_sent_callback); + espconn_regist_disconcb(conn, esp_socket_disconnect_callback); + espconn_regist_time(conn, 15, 0); + + if (esp_socket_listening->cb_connect != mp_const_none) { + call_function_1_protected(esp_socket_listening->cb_connect, s); + } else { + mp_obj_list_append(esp_socket_listening->connlist, s); + } +} + +STATIC void esp_socket_connect_callback_client(void *arg) { + struct espconn *conn = arg; + esp_socket_obj_t *s = conn->reverse; + + if (s->cb_connect != mp_const_none) { + call_function_1_protected(s->cb_connect, s); + } +} + +// method socket.listen(backlog) +STATIC mp_obj_t esp_socket_listen(mp_obj_t self_in, mp_obj_t backlog) { + esp_socket_obj_t *s = self_in; + + if (esp_socket_listening != NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "only one espconn can listen at a time")); + } + + esp_socket_listening = s; + + s->connlist = mp_obj_new_list(0, NULL); + + espconn_regist_connectcb(s->espconn, esp_socket_connect_callback_server); + espconn_accept(s->espconn); + espconn_regist_time(s->espconn, 1500, 0); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_listen_obj, esp_socket_listen); + +// method socket.accept() +STATIC mp_obj_t esp_socket_accept(mp_obj_t self_in) { + esp_socket_obj_t *s = self_in; + + if (s->connlist == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "not listening")); + } + + do { + mp_uint_t len; + mp_obj_t *items; + + mp_obj_list_get(s->connlist, &len, &items); + if (len == 0) { + break; + } + + esp_socket_obj_t *rs = items[0]; + mp_obj_list_remove(s->connlist, rs); + if (rs->espconn->state != ESPCONN_CLOSE) { + return rs; + } + } while (true); + + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "no connection in queue")); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(esp_socket_accept_obj, esp_socket_accept); + +// method socket.connect(address) +STATIC mp_obj_t esp_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + esp_socket_obj_t *s = self_in; + + if (s->espconn == NULL || s->espconn->state != ESPCONN_NONE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "transport endpoint is already connected or closed")); + } + + espconn_regist_connectcb(s->espconn, esp_socket_connect_callback_client); + espconn_regist_recvcb(s->espconn, esp_socket_recv_callback); + espconn_regist_sentcb(s->espconn, esp_socket_sent_callback); + espconn_regist_disconcb(s->espconn, esp_socket_disconnect_callback); + + s->espconn->proto.tcp->remote_port = + netutils_parse_inet_addr(addr_in, s->espconn->proto.tcp->remote_ip, + NETUTILS_BIG); + espconn_connect(s->espconn); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_connect_obj, esp_socket_connect); + +// method socket.send(bytes) +STATIC mp_obj_t esp_socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + esp_socket_obj_t *s = self_in; + + if (s->espconn->state == ESPCONN_NONE || s->espconn->state == ESPCONN_CLOSE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "not connected")); + } + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + + espconn_sent(s->espconn, bufinfo.buf, bufinfo.len); + + return mp_obj_new_int(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_send_obj, esp_socket_send); + +// method socket.recv(bufsize) +STATIC mp_obj_t esp_socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + esp_socket_obj_t *s = self_in; + + if (s->recvbuf == NULL) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, + "no data available")); + } + + mp_uint_t mxl = mp_obj_get_int(len_in); + if (mxl >= s->recvbuf_len) { + mp_obj_t trt = mp_obj_new_bytes(s->recvbuf, s->recvbuf_len); + gc_free(s->recvbuf); + s->recvbuf = NULL; + return trt; + } else { + mp_obj_t trt = mp_obj_new_bytes(s->recvbuf, mxl); + memmove(s->recvbuf, &s->recvbuf[mxl], s->recvbuf_len - mxl); + s->recvbuf_len -= mxl; + s->recvbuf = gc_realloc(s->recvbuf, s->recvbuf_len); + return trt; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_recv_obj, esp_socket_recv); + +// method socket.sendto(bytes, address) +STATIC mp_obj_t esp_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "UDP not supported")); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_socket_sendto_obj, esp_socket_sendto); + +// method socket.recvfrom(bufsize) +STATIC mp_obj_t esp_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "UDP not supported")); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_recvfrom_obj, esp_socket_recvfrom); + +STATIC mp_obj_t esp_socket_onconnect(mp_obj_t self_in, mp_obj_t lambda_in) { + esp_socket_obj_t *s = self_in; + s->cb_connect = lambda_in; + + if (s->connlist != NULL) { + do { + mp_uint_t len; + mp_obj_t *items; + + mp_obj_list_get(s->connlist, &len, &items); + if (len == 0) { + break; + } + + esp_socket_obj_t *rs = items[0]; + mp_obj_list_remove(s->connlist, rs); + if (s->espconn->state != ESPCONN_CLOSE) { + call_function_1_protected(s->cb_connect, rs); + } + } while (true); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_onconnect_obj, esp_socket_onconnect); + +STATIC mp_obj_t esp_socket_onrecv(mp_obj_t self_in, mp_obj_t lambda_in) { + esp_socket_obj_t *s = self_in; + s->cb_recv = lambda_in; + if (s->recvbuf != NULL) { + call_function_2_protected(s->cb_recv, s, + mp_obj_new_bytes((byte *)s->recvbuf, s->recvbuf_len)); + s->recvbuf = NULL; + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_onrecv_obj, esp_socket_onrecv); + +STATIC mp_obj_t esp_socket_ondisconnect(mp_obj_t self_in, mp_obj_t lambda_in) { + esp_socket_obj_t *s = self_in; + s->cb_disconnect = lambda_in; + + if (s->espconn->state == ESPCONN_CLOSE) { + call_function_1_protected(s->cb_disconnect, s); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(esp_socket_ondisconnect_obj, esp_socket_ondisconnect); + +typedef struct _esp_getaddrinfo_cb_struct_t { + mp_obj_t lambda; + mp_uint_t port; +} esp_getaddrinfo_cb_struct_t; + +STATIC esp_getaddrinfo_cb_struct_t esp_getaddrinfo_cb_struct; + +STATIC void esp_getaddrinfo_cb(const char *name, ip_addr_t *ipaddr, void *arg) { + mp_obj_t namestr = mp_obj_new_str(name, strlen(name), true); + if (ipaddr != NULL) { + uint8_t ip[4]; + ip[0] = (ipaddr->addr >> 24) & 0xff; + ip[1] = (ipaddr->addr >> 16) & 0xff; + ip[2] = (ipaddr->addr >> 8) & 0xff; + ip[3] = (ipaddr->addr >> 0) & 0xff; + + mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); + + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = netutils_format_inet_addr(ip, + esp_getaddrinfo_cb_struct.port, NETUTILS_BIG); + call_function_2_protected(esp_getaddrinfo_cb_struct.lambda, namestr, tuple); + } else { + call_function_2_protected(esp_getaddrinfo_cb_struct.lambda, namestr, mp_const_none); + } +} + +STATIC mp_obj_t esp_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in, + mp_obj_t lambda_in) { + mp_uint_t hlen; + const char *host = mp_obj_str_get_data(host_in, &hlen); + ip_addr_t ipaddr; + + esp_getaddrinfo_cb_struct.lambda = lambda_in; + esp_getaddrinfo_cb_struct.port = mp_obj_get_int(port_in); + + err_t ret = espconn_gethostbyname(NULL, host, &ipaddr, + esp_getaddrinfo_cb); + + if (ret == ESPCONN_OK) { + esp_getaddrinfo_cb(host, &ipaddr, NULL); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(esp_getaddrinfo_obj, esp_getaddrinfo); + +STATIC const mp_map_elem_t esp_socket_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&esp_socket___del___obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&esp_socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&esp_socket_bind_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&esp_socket_listen_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&esp_socket_accept_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&esp_socket_connect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&esp_socket_send_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&esp_socket_recv_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&esp_socket_sendto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&esp_socket_recvfrom_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_onconnect), (mp_obj_t)&esp_socket_onconnect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_onrecv), (mp_obj_t)&esp_socket_onrecv_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ondisconnect), (mp_obj_t)&esp_socket_ondisconnect_obj }, +}; +STATIC MP_DEFINE_CONST_DICT(esp_socket_locals_dict, esp_socket_locals_dict_table); + +STATIC const mp_obj_type_t esp_socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .make_new = esp_socket_make_new, + .locals_dict = (mp_obj_t)&esp_socket_locals_dict, +}; #define MODESP_INCLUDE_CONSTANTS (1) -// Singleton instance of scan callback, meaning that there can be only -// one concurrent AP scan. -STATIC mp_obj_t scan_cb_obj; - static void error_check(bool status, const char *msg) { if (!status) { nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, msg)); } } -mp_obj_t call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - return mp_call_function_1(fun, arg); - } else { - mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); - return (mp_obj_t)nlr.ret_val; - } -} - STATIC void esp_scan_cb(scaninfo *si, STATUS status) { //printf("in pyb_scan_cb: %d, si=%p, si->pbss=%p\n", status, si, si->pbss); struct bss_info *bs; @@ -70,13 +484,13 @@ STATIC void esp_scan_cb(scaninfo *si, STATUS status) { t->items[3] = MP_OBJ_NEW_SMALL_INT(bs->rssi); t->items[4] = MP_OBJ_NEW_SMALL_INT(bs->authmode); t->items[5] = MP_OBJ_NEW_SMALL_INT(bs->is_hidden); - call_function_1_protected(scan_cb_obj, t); + call_function_1_protected(MP_STATE_PORT(scan_cb_obj), t); } } } STATIC mp_obj_t esp_scan(mp_obj_t cb_in) { - scan_cb_obj = cb_in; + MP_STATE_PORT(scan_cb_obj) = cb_in; wifi_set_opmode(STATION_MODE); wifi_station_scan(NULL, (scan_done_cb_t)esp_scan_cb); return mp_const_none; @@ -118,6 +532,8 @@ STATIC const mp_map_elem_t esp_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&esp_disconnect_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_scan), (mp_obj_t)&esp_scan_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_status), (mp_obj_t)&esp_status_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&esp_getaddrinfo_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&esp_socket_type }, #if MODESP_INCLUDE_CONSTANTS { MP_OBJ_NEW_QSTR(MP_QSTR_STAT_IDLE), diff --git a/esp8266/mpconfigport.h b/esp8266/mpconfigport.h index dcd9407f82..cae5398f97 100644 --- a/esp8266/mpconfigport.h +++ b/esp8266/mpconfigport.h @@ -71,7 +71,11 @@ extern const struct _mp_obj_module_t esp_module; #define MP_STATE_PORT MP_STATE_VM #define MICROPY_PORT_ROOT_POINTERS \ - const char *readline_hist[8]; + const char *readline_hist[8]; \ + \ + /* Singleton instance of scan callback, meaning that there can + be only one concurrent AP scan. */ \ + mp_obj_t scan_cb_obj; \ // We need to provide a declaration/definition of alloca() #include diff --git a/esp8266/qstrdefsport.h b/esp8266/qstrdefsport.h index 26fce54de7..fb064095e4 100644 --- a/esp8266/qstrdefsport.h +++ b/esp8266/qstrdefsport.h @@ -42,10 +42,27 @@ Q(sync) Q(hard_reset) Q(esp) +Q(socket) Q(connect) Q(disconnect) Q(scan) Q(status) +Q(getaddrinfo) +Q(send) +Q(sendto) +Q(recv) +Q(recvfrom) +Q(listen) +Q(accept) +Q(bind) +Q(settimeout) +Q(setblocking) +Q(setsockopt) +Q(close) +Q(protocol) +Q(onconnect) +Q(onrecv) +Q(ondisconnect) Q(STAT_IDLE) Q(STAT_CONNECTING) Q(STAT_WRONG_PASSWORD) diff --git a/esp8266/utils.c b/esp8266/utils.c new file mode 100644 index 0000000000..e91ebe318d --- /dev/null +++ b/esp8266/utils.c @@ -0,0 +1,50 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2015 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/runtime.h" +#include "py/obj.h" +#include "py/nlr.h" + +mp_obj_t call_function_1_protected(mp_obj_t fun, mp_obj_t arg) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + return mp_call_function_1(fun, arg); + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + return (mp_obj_t)nlr.ret_val; + } +} + +mp_obj_t call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + return mp_call_function_2(fun, arg1, arg2); + } else { + mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); + return (mp_obj_t)nlr.ret_val; + } +} diff --git a/esp8266/utils.h b/esp8266/utils.h new file mode 100644 index 0000000000..ceef9720e8 --- /dev/null +++ b/esp8266/utils.h @@ -0,0 +1,29 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Josef Gajdusek + * Copyright (c) 2015 Paul Sokolovsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +mp_obj_t call_function_1_protected(mp_obj_t fun, mp_obj_t arg); +mp_obj_t call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2);