From 3a1c4c5bc6212310f5c0469300263290758217d7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 30 Sep 2014 22:29:49 +0100 Subject: [PATCH] stmhal: Add network and usocket module. As per issue #876, the network module is used to configure NICs (hardware modules) and configure routing. The usocket module is supposed to implement the normal Python socket module and selects the underlying NIC using routing logic. Right now the routing logic is brain dead: first-initialised, first-used. And the routing table is just a list of registered NICs. cc3k and wiznet5k work, but not at the same time due to C name clashes (to be fixed). Note that the usocket module has alias socket, so that one can import socket and it works as normal. But you can also override socket with your own module, using usocket at the backend. --- stmhal/Makefile | 2 + stmhal/main.c | 5 +- stmhal/modcc3k.c | 211 +++++++++++++++----------------------- stmhal/modnetwork.c | 141 ++++++++++++++++++++++++++ stmhal/modnetwork.h | 54 ++++++++++ stmhal/modusocket.c | 149 +++++++++++++++++++++++++++ stmhal/modwiznet5k.c | 230 ++++++++++++++---------------------------- stmhal/mpconfigport.h | 21 +--- stmhal/portmodules.h | 1 + stmhal/qstrdefsport.h | 34 ++++--- 10 files changed, 532 insertions(+), 316 deletions(-) create mode 100644 stmhal/modnetwork.c create mode 100644 stmhal/modnetwork.h create mode 100644 stmhal/modusocket.c diff --git a/stmhal/Makefile b/stmhal/Makefile index f14a881c5b..ba844d97cc 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -103,6 +103,8 @@ SRC_C = \ modstm.c \ modtime.c \ modselect.c \ + modusocket.c \ + modnetwork.c \ import.c \ lexerfatfs.c \ extint.c \ diff --git a/stmhal/main.c b/stmhal/main.c index 84ce6353a4..20db6ca4a3 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -64,11 +64,10 @@ #include "dac.h" #include "pybwlan.h" #include "pybstdio.h" +#include "modnetwork.h" void SystemClock_Config(void); -int errno; - static FATFS fatfs0; #if MICROPY_HW_HAS_SDCARD static FATFS fatfs1; @@ -510,6 +509,8 @@ soft_reset: pyb_wlan_start(); #endif + mod_network_init(); + // At this point everything is fully configured and initialised. // Run the main script from the current directory. diff --git a/stmhal/modcc3k.c b/stmhal/modcc3k.c index dda8d06f67..71b29fb86d 100644 --- a/stmhal/modcc3k.c +++ b/stmhal/modcc3k.c @@ -44,8 +44,10 @@ #include "qstr.h" #include "obj.h" #include "objtuple.h" +#include "objlist.h" #include "stream.h" #include "runtime.h" +#include "modnetwork.h" #include "pin.h" #include "genhdr/pins.h" #include "spi.h" @@ -61,10 +63,9 @@ #include "netapp.h" #include "patch_prog.h" -STATIC const mp_obj_type_t cc3k_type; -STATIC const mp_obj_type_t cc3k_socket_type; +int errno; // for cc3000 driver -STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol); +STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol, int *_errno); STATIC volatile uint32_t fd_closed_state = 0; STATIC volatile bool wlan_connected = false; @@ -102,6 +103,42 @@ STATIC void cc3k_callback(long event_type, char *data, unsigned char length) { } } +STATIC mp_obj_t cc3k_socket(mp_obj_t nic, int domain, int type, int fileno, int *_errno) { + switch (domain) { + case MOD_NETWORK_AF_INET: domain = AF_INET; break; + case MOD_NETWORK_AF_INET6: domain = AF_INET6; break; + default: *_errno = EAFNOSUPPORT; return MP_OBJ_NULL; + } + + switch (type) { + case MOD_NETWORK_SOCK_STREAM: type = SOCK_STREAM; break; + case MOD_NETWORK_SOCK_DGRAM: type = SOCK_DGRAM; break; + case MOD_NETWORK_SOCK_RAW: type = SOCK_RAW; break; + default: *_errno = EINVAL; return MP_OBJ_NULL; + } + + return cc3k_socket_new(domain, type, 0, _errno); +} + +STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { + uint32_t ip; + if (gethostbyname((char*)name, len, &ip) < 0) { + return errno; + } + + if (ip == 0) { + // unknown host + return ENOENT; + } + + out_ip[0] = ip >> 24; + out_ip[1] = ip >> 16; + out_ip[2] = ip >> 8; + out_ip[3] = ip; + + return 0; +} + /******************************************************************************/ // Micro Python bindings; CC3k class @@ -148,54 +185,54 @@ STATIC mp_obj_t cc3k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE); cc3k_obj_t *cc3k = m_new_obj(cc3k_obj_t); - cc3k->base.type = &cc3k_type; + cc3k->base.type = (mp_obj_type_t*)&mod_network_nic_type_cc3k; + + // register with network module + mod_network_register_nic(cc3k); return cc3k; } -STATIC mp_obj_t cc3k_connect(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - int ssid_len =0; - const char *ssid = NULL; - const char *bssid = NULL; +/// \method connect(ssid, key=None, *, security=WPA2, bssid=None) +STATIC mp_obj_t cc3k_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_key, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_security, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = WLAN_SEC_WPA2} }, + { MP_QSTR_bssid, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; - int key_len =0; - int sec = WLAN_SEC_UNSEC; - const char *key = NULL; + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_map_elem_t *kw_key, *kw_sec, *kw_bssid; - - ssid = mp_obj_str_get_str(args[1]); - ssid_len = strlen(ssid); - - // get KW args - kw_key = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("key")), MP_MAP_LOOKUP); - kw_sec = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("sec")), MP_MAP_LOOKUP); - kw_bssid = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("bssid")), MP_MAP_LOOKUP); + // get ssid + mp_uint_t ssid_len; + const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len); // get key and sec - if (kw_key && kw_sec) { - key = mp_obj_str_get_str(kw_key->value); - key_len = strlen(key); - - sec = mp_obj_get_int(kw_sec->value); - if (!(WLAN_SEC_UNSEC < sec && sec <= WLAN_SEC_WPA2)) { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid security mode")); - } + mp_uint_t key_len = 0; + const char *key = NULL; + mp_uint_t sec = WLAN_SEC_UNSEC; + if (args[1].u_obj != mp_const_none) { + key = mp_obj_str_get_data(args[1].u_obj, &key_len); + sec = args[2].u_int; } // get bssid - if (kw_bssid != NULL) { - bssid = mp_obj_str_get_str(kw_bssid->value); + const char *bssid = NULL; + if (args[3].u_obj != mp_const_none) { + bssid = mp_obj_str_get_str(args[3].u_obj); } // connect to AP - if (wlan_connect(sec, (char*) ssid, ssid_len, (uint8_t*)bssid, (uint8_t*)key, key_len) != 0) { + if (wlan_connect(sec, (char*)ssid, ssid_len, (uint8_t*)bssid, (uint8_t*)key, key_len) != 0) { nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "could not connect to ssid=%s, sec=%d, key=%s\n", ssid, sec, key)); } return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(cc3k_connect_obj, 2, cc3k_connect); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(cc3k_connect_obj, 1, cc3k_connect); STATIC mp_obj_t cc3k_disconnect(mp_obj_t self_in) { int ret = wlan_disconnect(); @@ -259,49 +296,6 @@ STATIC mp_obj_t cc3k_patch_program(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_patch_program_obj, cc3k_patch_program); -/// \method socket(family=AF_INET, type=SOCK_STREAM, fileno=-1) -/// Create a socket. -STATIC const mp_arg_t cc3k_socket_args[] = { - { MP_QSTR_family, MP_ARG_INT, {.u_int = AF_INET} }, - { MP_QSTR_type, MP_ARG_INT, {.u_int = SOCK_STREAM} }, -}; -#define PYB_CC3K_SOCKET_NUM_ARGS MP_ARRAY_SIZE(cc3k_socket_args) -STATIC mp_obj_t cc3k_socket(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - // parse args - mp_arg_val_t vals[PYB_CC3K_SOCKET_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_CC3K_SOCKET_NUM_ARGS, cc3k_socket_args, vals); - - return cc3k_socket_new(vals[0].u_int, vals[1].u_int, 0); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(cc3k_socket_obj, 1, cc3k_socket); - -STATIC mp_obj_t cc3k_gethostbyname(mp_obj_t self_in, mp_obj_t hostname) { - mp_uint_t len; - const char *host = mp_obj_str_get_data(hostname, &len); - uint32_t ip; - - if (gethostbyname((char*)host, len, &ip) < 0) { - // TODO raise appropriate exception - printf("gethostbyname failed\n"); - return mp_const_none; - } - - if (ip == 0) { - // unknown host - // TODO CPython raises: socket.gaierror: [Errno -2] Name or service not known - printf("Name or service not known\n"); - return mp_const_none; - } - - // turn the ip address into a string (could use inet_ntop, but this here is much more efficient) - VSTR_FIXED(ip_str, 16); - vstr_printf(&ip_str, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); - mp_obj_t ret = mp_obj_new_str(ip_str.buf, ip_str.len, false); - - return ret; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_gethostbyname_obj, cc3k_gethostbyname); - STATIC const mp_map_elem_t cc3k_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&cc3k_connect_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&cc3k_disconnect_obj }, @@ -310,37 +304,24 @@ STATIC const mp_map_elem_t cc3k_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_patch_version), (mp_obj_t)&cc3k_patch_version_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_patch_program), (mp_obj_t)&cc3k_patch_program_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&cc3k_socket_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_gethostbyname), (mp_obj_t)&cc3k_gethostbyname_obj }, - // class constants - { MP_OBJ_NEW_QSTR(MP_QSTR_WEP), MP_OBJ_NEW_SMALL_INT(WLAN_SEC_WEP) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WPA), MP_OBJ_NEW_SMALL_INT(WLAN_SEC_WPA) }, { MP_OBJ_NEW_QSTR(MP_QSTR_WPA2), MP_OBJ_NEW_SMALL_INT(WLAN_SEC_WPA2) }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IP), MP_OBJ_NEW_SMALL_INT(IPPROTO_IP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_ICMP), MP_OBJ_NEW_SMALL_INT(IPPROTO_ICMP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IPV4), MP_OBJ_NEW_SMALL_INT(IPPROTO_IPV4) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IPV6), MP_OBJ_NEW_SMALL_INT(IPPROTO_IPV6) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(IPPROTO_RAW) }, }; STATIC MP_DEFINE_CONST_DICT(cc3k_locals_dict, cc3k_locals_dict_table); -STATIC const mp_obj_type_t cc3k_type = { - { &mp_type_type }, - .name = MP_QSTR_CC3k, - //.print = cc3k_print, - .make_new = cc3k_make_new, - .locals_dict = (mp_obj_t)&cc3k_locals_dict, +const mod_network_nic_type_t mod_network_nic_type_cc3k = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_CC3k, + //.print = cc3k_print, + .make_new = cc3k_make_new, + .locals_dict = (mp_obj_t)&cc3k_locals_dict, + }, + .socket = cc3k_socket, + .gethostbyname = cc3k_gethostbyname, }; /******************************************************************************/ @@ -355,7 +336,9 @@ typedef struct _cc3k_socket_obj_t { int fd; } cc3k_socket_obj_t; -STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol) { +STATIC const mp_obj_type_t cc3k_socket_type; + +STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol, int *_errno) { // create socket object cc3k_socket_obj_t *s = m_new_obj_with_finaliser(cc3k_socket_obj_t); s->base.type = (mp_obj_t)&cc3k_socket_type; @@ -364,7 +347,8 @@ STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t prot s->fd = socket(family, type, protocol); if (s->fd < 0) { m_del_obj(cc3k_socket_obj_t, s); - nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "socket failed")); + *_errno = errno; + return MP_OBJ_NULL; } // clear socket state @@ -667,33 +651,6 @@ STATIC const mp_obj_type_t cc3k_socket_type = { { &mp_type_type }, .name = MP_QSTR_socket, .print = cc3k_socket_print, - .getiter = NULL, - .iternext = NULL, .stream_p = &cc3k_socket_stream_p, .locals_dict = (mp_obj_t)&cc3k_socket_locals_dict, }; - -/******************************************************************************/ -// Micro Python bindings; CC3k module - -STATIC const mp_map_elem_t mp_module_cc3k_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_cc3k) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CC3k), (mp_obj_t)&cc3k_type }, -}; - -STATIC const mp_obj_dict_t mp_module_cc3k_globals = { - .base = {&mp_type_dict}, - .map = { - .all_keys_are_qstrs = 1, - .table_is_fixed_array = 1, - .used = MP_ARRAY_SIZE(mp_module_cc3k_globals_table), - .alloc = MP_ARRAY_SIZE(mp_module_cc3k_globals_table), - .table = (mp_map_elem_t*)mp_module_cc3k_globals_table, - }, -}; - -const mp_obj_module_t mp_module_cc3k = { - .base = { &mp_type_module }, - .name = MP_QSTR_cc3k, - .globals = (mp_obj_dict_t*)&mp_module_cc3k_globals, -}; diff --git a/stmhal/modnetwork.c b/stmhal/modnetwork.c new file mode 100644 index 0000000000..a0cd24de6b --- /dev/null +++ b/stmhal/modnetwork.c @@ -0,0 +1,141 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * 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 +#include +#include +#include + +#include "stm32f4xx_hal.h" + +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "objlist.h" +#include "runtime.h" +#include "modnetwork.h" + +mp_obj_list_t mod_network_nic_list; + +void mod_network_init(void) { + mp_obj_list_init(&mod_network_nic_list, 0); +} + +void mod_network_register_nic(mp_obj_t nic) { + for (mp_uint_t i = 0; i < mod_network_nic_list.len; i++) { + if (mod_network_nic_list.items[i] == nic) { + // nic already registered + return; + } + } + // nic not registered so add to list + mp_obj_list_append(&mod_network_nic_list, nic); +} + +STATIC mp_obj_t network_route(void) { + return &mod_network_nic_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(network_route_obj, network_route); + +STATIC const mp_map_elem_t mp_module_network_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_network) }, + + #if MICROPY_PY_WIZNET5K + { MP_OBJ_NEW_QSTR(MP_QSTR_WIZnet5k), (mp_obj_t)&mod_network_nic_type_wiznet5k }, + #endif + #if MICROPY_PY_CC3K + { MP_OBJ_NEW_QSTR(MP_QSTR_CC3k), (mp_obj_t)&mod_network_nic_type_cc3k }, + #endif + + { MP_OBJ_NEW_QSTR(MP_QSTR_route), (mp_obj_t)&network_route_obj }, +}; + +STATIC const mp_obj_dict_t mp_module_network_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = MP_ARRAY_SIZE(mp_module_network_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_network_globals_table), + .table = (mp_map_elem_t*)mp_module_network_globals_table, + }, +}; + +const mp_obj_module_t mp_module_network = { + .base = { &mp_type_module }, + .name = MP_QSTR_network, + .globals = (mp_obj_dict_t*)&mp_module_network_globals, +}; + +/******************************************************************************/ +// Miscellaneous helpers + +void mod_network_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip) { + const char *addr_str = mp_obj_str_get_str(addr_in); + const char *s = addr_str; + for (mp_uint_t i = 0;; i++) { + mp_uint_t val = 0; + for (; *s && *s != '.'; s++) { + val = val * 10 + *s - '0'; + } + out_ip[i] = val; + if (i == 3 && *s == '\0') { + return; + } else if (i < 3 && *s == '.') { + s++; + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid IP address")); + } + } +} + +// Takes an address of the form ('192.168.0.1', 8080), returns the port and +// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). +mp_uint_t mod_network_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip) { + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); + mod_network_parse_ipv4_addr(addr_items[0], out_ip); + return mp_obj_get_int(addr_items[1]); +} + +// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. +mp_obj_t mod_network_format_ipv4_addr(uint8_t *ip) { + char ip_str[16]; + mp_uint_t ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + return mp_obj_new_str(ip_str, ip_len, false); +} + +// Takes an array with a raw IP address, and a port, and returns a net-address +// tuple such as ('192.168.0.1', 8080). +mp_obj_t mod_network_format_inet_addr(uint8_t *ip, mp_uint_t port) { + mp_obj_t tuple[2] = { + tuple[0] = mod_network_format_ipv4_addr(ip), + tuple[1] = mp_obj_new_int(port), + }; + return mp_obj_new_tuple(2, tuple); +} diff --git a/stmhal/modnetwork.h b/stmhal/modnetwork.h new file mode 100644 index 0000000000..ed31a602f2 --- /dev/null +++ b/stmhal/modnetwork.h @@ -0,0 +1,54 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * 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. + */ + +#define MOD_NETWORK_IPADDR_BUF_SIZE (4) + +#define MOD_NETWORK_AF_INET (2) +#define MOD_NETWORK_AF_INET6 (10) + +#define MOD_NETWORK_SOCK_STREAM (1) +#define MOD_NETWORK_SOCK_DGRAM (2) +#define MOD_NETWORK_SOCK_RAW (3) + +typedef struct _mod_network_nic_type_t { + mp_obj_type_t base; + + // API for a generic NIC + mp_obj_t (*socket)(mp_obj_t nic, int domain, int type, int fileno, int *_errno); + int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out); +} mod_network_nic_type_t; + +extern struct _mp_obj_list_t mod_network_nic_list; +extern const mod_network_nic_type_t mod_network_nic_type_wiznet5k; +extern const mod_network_nic_type_t mod_network_nic_type_cc3k; + +void mod_network_init(void); +void mod_network_register_nic(mp_obj_t nic); + +void mod_network_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip); +mp_uint_t mod_network_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip); +mp_obj_t mod_network_format_ipv4_addr(uint8_t *ip); +mp_obj_t mod_network_format_inet_addr(uint8_t *ip, mp_uint_t port); diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c new file mode 100644 index 0000000000..6a544cb3e0 --- /dev/null +++ b/stmhal/modusocket.c @@ -0,0 +1,149 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2014 Damien P. George + * + * 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 +#include +#include +#include + +#include "stm32f4xx_hal.h" + +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "objtuple.h" +#include "objlist.h" +#include "runtime.h" +#include "modnetwork.h" + +/// \module usocket + +/// \method socket(family=AF_INET, type=SOCK_STREAM, fileno=-1) +/// Create a socket. +STATIC mp_obj_t mod_usocket_socket(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_family, MP_ARG_INT, {.u_int = MOD_NETWORK_AF_INET} }, + { MP_QSTR_type, MP_ARG_INT, {.u_int = MOD_NETWORK_SOCK_STREAM} }, + { MP_QSTR_fileno, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, + }; + + // parse args + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // find a NIC that can create a socket and call it + for (mp_uint_t i = 0; i < mod_network_nic_list.len; i++) { + mp_obj_t nic = mod_network_nic_list.items[i]; + mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic); + if (nic_type->socket != NULL) { + int _errno; + mp_obj_t obj = nic_type->socket(nic, args[0].u_int, args[1].u_int, args[2].u_int, &_errno); + if (obj == MP_OBJ_NULL) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } else { + return obj; + } + } + } + + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC")); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_usocket_socket_obj, 0, mod_usocket_socket); + +/// \method getaddrinfo(host, port) +STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { + mp_uint_t hlen; + const char *host = mp_obj_str_get_data(host_in, &hlen); + mp_int_t port = mp_obj_get_int(port_in); + + // find a NIC that can do a name lookup + for (mp_uint_t i = 0; i < mod_network_nic_list.len; i++) { + mp_obj_t nic = mod_network_nic_list.items[i]; + mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic); + if (nic_type->gethostbyname != NULL) { + uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + int ret = nic_type->gethostbyname(nic, host, hlen, out_ip); + if (ret != 0) { + // TODO CPython raises: socket.gaierror: [Errno -2] Name or service not known + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ret))); + } + mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = mod_network_format_inet_addr(out_ip, port); + return mp_obj_new_list(1, (mp_obj_t*)&tuple); + } + } + + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC")); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo); + +STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mod_usocket_socket_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_usocket_getaddrinfo_obj }, + + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET6) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_DGRAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_RAW) }, + + /* + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IP), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_IP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_ICMP), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_ICMP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IPV4), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_IPV4) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_TCP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_UDP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IPV6), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_IPV6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_IPPROTO_RAW) }, + */ +}; + +STATIC const mp_obj_dict_t mp_module_usocket_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = MP_ARRAY_SIZE(mp_module_usocket_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_usocket_globals_table), + .table = (mp_map_elem_t*)mp_module_usocket_globals_table, + }, +}; + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .name = MP_QSTR_usocket, + .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, +}; diff --git a/stmhal/modwiznet5k.c b/stmhal/modwiznet5k.c index 3996c29944..3a4b25c0f6 100644 --- a/stmhal/modwiznet5k.c +++ b/stmhal/modwiznet5k.c @@ -36,7 +36,9 @@ #include "misc.h" #include "qstr.h" #include "obj.h" +#include "objlist.h" #include "runtime.h" +#include "modnetwork.h" #include "pin.h" #include "genhdr/pins.h" #include "spi.h" @@ -64,17 +66,14 @@ #define IPADDR_BUF_SIZE (4) -STATIC const mp_obj_type_t wiznet5k_type; -STATIC const mp_obj_type_t wiznet5k_socket_type; - STATIC mp_obj_t wiznet5k_socket_new(uint8_t sn, mp_uint_t type); typedef struct _wiznet5k_obj_t { mp_obj_base_t base; mp_uint_t cris_state; + SPI_HandleTypeDef *spi; const pin_obj_t *cs; const pin_obj_t *rst; - SPI_HandleTypeDef *spi; uint8_t socket_used; } wiznet5k_obj_t; @@ -106,9 +105,6 @@ STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) { (void)status; } -/******************************************************************************/ -// Miscellaneous helpers - // Check the return value from Wiz socket calls: // - on error (<0) an exception is raised // - SOCK_OK or SOCK_BUSY does nothing @@ -120,51 +116,50 @@ STATIC void check_sock_return_value(int8_t ret) { } } -STATIC void parse_ip_addr(mp_obj_t addr_in, uint8_t *out_ip) { - const char *addr_str = mp_obj_str_get_str(addr_in); - const char *s = addr_str; - for (mp_uint_t i = 0;; i++) { - mp_uint_t val = 0; - for (; *s && *s != '.'; s++) { - val = val * 10 + *s - '0'; +STATIC mp_obj_t wiznet5k_socket(mp_obj_t self_in, int domain, int type, int fileno, int *_errno) { + if (domain != MOD_NETWORK_AF_INET) { + *_errno = EAFNOSUPPORT; + return MP_OBJ_NULL; + } + + switch (type) { + case MOD_NETWORK_SOCK_STREAM: type = Sn_MR_TCP; break; + case MOD_NETWORK_SOCK_DGRAM: type = Sn_MR_UDP; break; + default: *_errno = EINVAL; return MP_OBJ_NULL; + } + + if (fileno < 0) { + // get first unused socket number + for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) { + if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) { + fileno = sn; + break; + } } - out_ip[i] = val; - if (i == 3 && *s == '\0') { - return; - } else if (i < 3 && *s == '.') { - s++; - } else { - nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid IP address")); + if (fileno < 0) { + // too many open sockets + *_errno = EMFILE; + return MP_OBJ_NULL; } } + + return wiznet5k_socket_new(fileno, type); } -// Takes an address of the form ('192.168.0.1', 8080), returns the port and -// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). -STATIC mp_uint_t parse_net_addr(mp_obj_t addr_in, uint8_t *out_ip) { - mp_obj_t *addr_items; - mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); - parse_ip_addr(addr_items[0], out_ip); - return mp_obj_get_int(addr_items[1]); +STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { + uint8_t dns_ip[IPADDR_BUF_SIZE] = {8, 8, 8, 8}; + uint8_t *buf = m_new(uint8_t, MAX_DNS_BUF_SIZE); + DNS_init(0, buf); + mp_int_t ret = DNS_run(dns_ip, (uint8_t*)name, out_ip); + m_del(uint8_t, buf, MAX_DNS_BUF_SIZE); + if (ret == 1) { + // success + return 0; + } else { + // failure + return ENOENT; + } } - -// Takes an array with a raw IP address and returns something like '192.168.0.1'. -STATIC mp_obj_t format_ip_addr(uint8_t *ip) { - char ip_str[16]; - mp_uint_t ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); - return mp_obj_new_str(ip_str, ip_len, false); -} - -// Takes an array with a raw IP address, and a port, and returns a net-address -// tuple such as ('192.168.0.1', 8080). -STATIC mp_obj_t format_net_addr(uint8_t *ip, mp_uint_t port) { - mp_obj_t tuple[2] = { - tuple[0] = format_ip_addr(ip), - tuple[1] = mp_obj_new_int(port), - }; - return mp_obj_new_tuple(2, tuple); -} - /******************************************************************************/ // Micro Python bindings @@ -174,18 +169,18 @@ STATIC void wiznet5k_print(void (*print)(void *env, const char *fmt, ...), void print(env, "WIZnet5k()"); } -/// \classmethod \constructor() +/// \classmethod \constructor(spi, pin_cs, pin_rst) /// Create and return a WIZnet5k object. STATIC mp_obj_t wiznet5k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { // check arguments - mp_arg_check_num(n_args, n_kw, 0, 0, false); + mp_arg_check_num(n_args, n_kw, 3, 3, false); // init the wiznet5k object - wiznet5k_obj.base.type = &wiznet5k_type; + wiznet5k_obj.base.type = (mp_obj_type_t*)&mod_network_nic_type_wiznet5k; wiznet5k_obj.cris_state = 0; - wiznet5k_obj.cs = &pin_B12; // Y5 - wiznet5k_obj.rst = &pin_B9; // Y4 - wiznet5k_obj.spi = &SPIHandle2; // Y-skin + wiznet5k_obj.spi = spi_get_handle(args[0]); + wiznet5k_obj.cs = pin_find(args[1]); + wiznet5k_obj.rst = pin_find(args[2]); wiznet5k_obj.socket_used = 0; /*!< SPI configuration */ @@ -200,7 +195,7 @@ STATIC mp_obj_t wiznet5k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t SPIHandle2.Init.TIMode = SPI_TIMODE_DISABLED; SPIHandle2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; SPIHandle2.Init.CRCPolynomial = 7; // unused - spi_init(wiznet5k_obj.spi); + spi_init(wiznet5k_obj.spi, false); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; @@ -238,6 +233,9 @@ STATIC mp_obj_t wiznet5k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t }; ctlnetwork(CN_SET_NETINFO, (void*)&netinfo); + // register with network module + mod_network_register_nic(&wiznet5k_obj); + // return wiznet5k object return &wiznet5k_obj; } @@ -275,98 +273,43 @@ STATIC mp_obj_t wiznet5k_ipaddr(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 1) { // get mp_obj_t tuple[4] = { - format_ip_addr(netinfo.ip), - format_ip_addr(netinfo.sn), - format_ip_addr(netinfo.gw), - format_ip_addr(netinfo.dns), + mod_network_format_ipv4_addr(netinfo.ip), + mod_network_format_ipv4_addr(netinfo.sn), + mod_network_format_ipv4_addr(netinfo.gw), + mod_network_format_ipv4_addr(netinfo.dns), }; return mp_obj_new_tuple(4, tuple); } else { // set mp_obj_t *items; mp_obj_get_array_fixed_n(args[1], 4, &items); - parse_ip_addr(items[0], netinfo.ip); - parse_ip_addr(items[1], netinfo.sn); - parse_ip_addr(items[2], netinfo.gw); - parse_ip_addr(items[3], netinfo.dns); + mod_network_parse_ipv4_addr(items[0], netinfo.ip); + mod_network_parse_ipv4_addr(items[1], netinfo.sn); + mod_network_parse_ipv4_addr(items[2], netinfo.gw); + mod_network_parse_ipv4_addr(items[3], netinfo.dns); ctlnetwork(CN_SET_NETINFO, &netinfo); return mp_const_none; } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ipaddr_obj, 1, 2, wiznet5k_ipaddr); -/// \method socket(family=AF_INET, type=SOCK_STREAM, fileno=-1) -/// Create a socket. -STATIC const mp_arg_t wiznet5k_socket_args[] = { - { MP_QSTR_family, MP_ARG_INT, {.u_int = 0} }, // ignored, only AF_INET supported - { MP_QSTR_type, MP_ARG_INT, {.u_int = Sn_MR_TCP} }, // SOCK_STREAM or SOCK_DGRAM - { MP_QSTR_fileno, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} }, -}; -#define PYB_WIZNET5K_SOCKET_NUM_ARGS MP_ARRAY_SIZE(wiznet5k_socket_args) - -STATIC mp_obj_t wiznet5k_socket(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - // parse args - mp_arg_val_t vals[PYB_WIZNET5K_SOCKET_NUM_ARGS]; - mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_WIZNET5K_SOCKET_NUM_ARGS, wiznet5k_socket_args, vals); - - if (vals[2].u_int < 0) { - // get first unused socket number - for (mp_uint_t sn = 0; sn < _WIZCHIP_SOCK_NUM_; sn++) { - if ((wiznet5k_obj.socket_used & (1 << sn)) == 0) { - vals[2].u_int = sn; - break; - } - } - if (vals[2].u_int < 0) { - // too many open sockets - nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EMFILE))); - } - } - - return wiznet5k_socket_new(vals[2].u_int, vals[1].u_int); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wiznet5k_socket_obj, 1, wiznet5k_socket); - -/// \method gethostbyname(name) -/// Use DNS to lookup a host name. Returns an IP address. -STATIC mp_obj_t wiznet5k_gethostbyname(mp_obj_t self_in, mp_obj_t name_in) { - uint8_t dns_ip[IPADDR_BUF_SIZE] = {8, 8, 8, 8}; - const char *name = mp_obj_str_get_str(name_in); - uint8_t out_ip[IPADDR_BUF_SIZE]; - uint8_t *buf = m_new(uint8_t, MAX_DNS_BUF_SIZE); - DNS_init(0, buf); - mp_int_t ret = DNS_run(dns_ip, (uint8_t*)name, out_ip); - m_del(uint8_t, buf, MAX_DNS_BUF_SIZE); - if (ret == 1) { - // success - return format_ip_addr(out_ip); - } else { - // failure - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "DNS error %d", ret)); - } -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_gethostbyname_obj, wiznet5k_gethostbyname); - STATIC const mp_map_elem_t wiznet5k_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_regs), (mp_obj_t)&wiznet5k_regs_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_ipaddr), (mp_obj_t)&wiznet5k_ipaddr_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&wiznet5k_socket_obj }, - { MP_OBJ_NEW_QSTR(MP_QSTR_gethostbyname), (mp_obj_t)&wiznet5k_gethostbyname_obj }, - - // class constants - { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(0) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(Sn_MR_TCP) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(Sn_MR_UDP) }, }; STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table); -STATIC const mp_obj_type_t wiznet5k_type = { - { &mp_type_type }, - .name = MP_QSTR_WIZnet5k, - .print = wiznet5k_print, - .make_new = wiznet5k_make_new, - .locals_dict = (mp_obj_t)&wiznet5k_locals_dict, +const mod_network_nic_type_t mod_network_nic_type_wiznet5k = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_WIZnet5k, + .print = wiznet5k_print, + .make_new = wiznet5k_make_new, + .locals_dict = (mp_obj_t)&wiznet5k_locals_dict, + }, + .socket = wiznet5k_socket, + .gethostbyname = wiznet5k_gethostbyname, }; /******************************************************************************/ @@ -378,6 +321,8 @@ typedef struct _wiznet5k_socket_obj_t { uint8_t type; } wiznet5k_socket_obj_t; +STATIC const mp_obj_type_t wiznet5k_socket_type; + STATIC mp_obj_t wiznet5k_socket_new(uint8_t sn, mp_uint_t type) { wiznet5k_socket_obj_t *s = m_new_obj(wiznet5k_socket_obj_t); s->base.type = &wiznet5k_socket_type; @@ -404,7 +349,7 @@ STATIC mp_obj_t wiznet5k_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { wiznet5k_socket_obj_t *self = self_in; uint8_t ip[IPADDR_BUF_SIZE]; - mp_uint_t port = parse_net_addr(addr_in, ip); + mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip); // open the socket in server mode mp_int_t ret = socket(self->sn, self->type, port, 0); @@ -441,7 +386,7 @@ STATIC mp_obj_t wiznet5k_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { // now connect uint8_t ip[IPADDR_BUF_SIZE]; - mp_uint_t port = parse_net_addr(addr_in, ip); + mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip); ret = connect(self->sn, ip, port); check_sock_return_value(ret); @@ -484,7 +429,7 @@ STATIC mp_obj_t wiznet5k_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_ob mp_buffer_info_t bufinfo; mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); uint8_t ip[IPADDR_BUF_SIZE]; - mp_uint_t port = parse_net_addr(addr_in, ip); + mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip); mp_int_t ret = sendto(self->sn, bufinfo.buf, bufinfo.len, ip, port); check_sock_return_value(ret); return mp_obj_new_int(ret); @@ -501,7 +446,7 @@ STATIC mp_obj_t wiznet5k_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { check_sock_return_value(ret); mp_obj_t tuple[2] = { mp_obj_new_bytes(buf, ret), - format_net_addr(ip, port), + mod_network_format_inet_addr(ip, port), }; return mp_obj_new_tuple(2, tuple); } @@ -528,28 +473,3 @@ STATIC const mp_obj_type_t wiznet5k_socket_type = { .print = wiznet5k_socket_print, .locals_dict = (mp_obj_t)&wiznet5k_socket_locals_dict, }; - -/******************************************************************************/ -// Micro Python bindings; WIZnet5x00 module - -STATIC const mp_map_elem_t mp_module_wiznet5k_globals_table[] = { - { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_wiznet5k) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_WIZnet5k), (mp_obj_t)&wiznet5k_type }, -}; - -STATIC const mp_obj_dict_t mp_module_wiznet5k_globals = { - .base = {&mp_type_dict}, - .map = { - .all_keys_are_qstrs = 1, - .table_is_fixed_array = 1, - .used = MP_ARRAY_SIZE(mp_module_wiznet5k_globals_table), - .alloc = MP_ARRAY_SIZE(mp_module_wiznet5k_globals_table), - .table = (mp_map_elem_t*)mp_module_wiznet5k_globals_table, - }, -}; - -const mp_obj_module_t mp_module_wiznet5k = { - .base = { &mp_type_module }, - .name = MP_QSTR_wiznet5k, - .globals = (mp_obj_dict_t*)&mp_module_wiznet5k_globals, -}; diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 8fe2f21027..e9b76414ad 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -77,20 +77,8 @@ extern const struct _mp_obj_module_t pyb_module; extern const struct _mp_obj_module_t stm_module; extern const struct _mp_obj_module_t time_module; extern const struct _mp_obj_module_t mp_module_select; - -#if MICROPY_PY_WIZNET5K -extern const struct _mp_obj_module_t mp_module_wiznet5k; -#define MICROPY_PY_WIZNET5K_DEF { MP_OBJ_NEW_QSTR(MP_QSTR_wiznet5k), (mp_obj_t)&mp_module_wiznet5k }, -#else -#define MICROPY_PY_WIZNET5K_DEF -#endif - -#if MICROPY_PY_CC3K -extern const struct _mp_obj_module_t mp_module_cc3k; -#define MICROPY_PY_CC3K_DEF { MP_OBJ_NEW_QSTR(MP_QSTR_cc3k), (mp_obj_t)&mp_module_cc3k }, -#else -#define MICROPY_PY_CC3K_DEF -#endif +extern const struct _mp_obj_module_t mp_module_usocket; +extern const struct _mp_obj_module_t mp_module_network; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \ @@ -98,8 +86,9 @@ extern const struct _mp_obj_module_t mp_module_cc3k; { MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_select }, \ - MICROPY_PY_WIZNET5K_DEF \ - MICROPY_PY_CC3K_DEF \ + { MP_OBJ_NEW_QSTR(MP_QSTR_usocket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&mp_module_usocket }, \ + { MP_OBJ_NEW_QSTR(MP_QSTR_network), (mp_obj_t)&mp_module_network }, \ // extra constants #define MICROPY_PORT_CONSTANTS \ diff --git a/stmhal/portmodules.h b/stmhal/portmodules.h index d71f74e73c..ebeaae796d 100644 --- a/stmhal/portmodules.h +++ b/stmhal/portmodules.h @@ -29,6 +29,7 @@ extern const mp_obj_module_t pyb_module; extern const mp_obj_module_t stm_module; extern const mp_obj_module_t time_module; extern const mp_obj_module_t mp_module_select; +extern const mp_obj_module_t mp_module_usocket; // additional helper functions exported by the modules diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index 674b8f3f8b..d0d8c113b8 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -320,6 +320,20 @@ Q(pixel) Q(text) Q(show) +// for usocket module +Q(usocket) +Q(socket) +Q(getaddrinfo) +Q(AF_INET) +Q(AF_INET6) +Q(SOCK_STREAM) +Q(SOCK_DGRAM) +Q(SOCK_RAW) + +// for network module +Q(network) +Q(route) + // for WIZnet5k class #if MICROPY_PY_WIZNET5K Q(wiznet5k) @@ -356,25 +370,13 @@ Q(is_connected) Q(ifconfig) Q(patch_version) Q(patch_program) -Q(socket) -Q(family) -Q(type) -Q(gethostbyname) Q(WEP) Q(WPA) Q(WPA2) -Q(AF_INET) -Q(AF_INET6) -Q(SOCK_STREAM) -Q(SOCK_DGRAM) -Q(SOCK_RAW) -Q(IPPROTO_IP) -Q(IPPROTO_ICMP) -Q(IPPROTO_IPV4) -Q(IPPROTO_TCP) -Q(IPPROTO_UDP) -Q(IPPROTO_IPV6) -Q(IPPROTO_RAW) +Q(ssid) +Q(key) +Q(security) +Q(bssid) Q(send) Q(recv) Q(bind)