Commit 3a1c4c5b authored by Damien George's avatar Damien George
Browse files

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.
parent bfa7b480
......@@ -103,6 +103,8 @@ SRC_C = \
modstm.c \
modtime.c \
modselect.c \
modusocket.c \
modnetwork.c \
import.c \
lexerfatfs.c \
extint.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.
......
......@@ -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;
int key_len =0;
int sec = WLAN_SEC_UNSEC;
const char *key = NULL;
mp_map_elem_t *kw_key, *kw_sec, *kw_bssid;
/// \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} },
};
ssid = mp_obj_str_get_str(args[1]);
ssid_len = strlen(ssid);
// 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);
// 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,
};
/*
* 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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#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);
}
/*
* 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);
/*
* 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 <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#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) {