diff options
| author | iabdalkader <i.abdalkader@gmail.com> | 2021-08-15 18:51:15 +0200 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2021-11-13 23:01:03 +1100 |
| commit | 43079aaf860cbc19d54cec1eca9d5897297b22ac (patch) | |
| tree | 2866b480af3d9b777f3a182ae99e275f4ef04ce0 /extmod/network_ninaw10.c | |
| parent | b6dbbbe82f7114cb5b56c54e916e304f416cd47a (diff) | |
drivers/ninaw10: Add ublox Nina-W10 WiFi/BT module driver.
- Add WiFi/BT drivers for ublox Nina-W10 (esp32 based) module.
- Add ublox Nina-W10 Python module in extmod.
Diffstat (limited to 'extmod/network_ninaw10.c')
| -rw-r--r-- | extmod/network_ninaw10.c | 588 |
1 files changed, 588 insertions, 0 deletions
diff --git a/extmod/network_ninaw10.c b/extmod/network_ninaw10.c new file mode 100644 index 000000000..aa4b8dd0c --- /dev/null +++ b/extmod/network_ninaw10.c @@ -0,0 +1,588 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2021 Ibrahim Abdelkader <iabdalkader@openmv.io> + * + * 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. + * + * NINA-W10 Python module. + */ + +#include "py/mphal.h" + +#if MICROPY_PY_NETWORK && MICROPY_PY_NETWORK_NINAW10 + +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> + +#include "py/objtuple.h" +#include "py/objlist.h" +#include "py/stream.h" +#include "py/runtime.h" +#include "py/misc.h" +#include "py/mperrno.h" +#include "shared/netutils/netutils.h" +#include "extmod/modnetwork.h" + +#include "nina_wifi_drv.h" + +typedef struct _nina_obj_t { + mp_obj_base_t base; + bool active; + uint32_t itf; +} nina_obj_t; + +// For auto-binding UDP sockets +#define BIND_PORT_RANGE_MIN (65000) +#define BIND_PORT_RANGE_MAX (65535) + +static uint16_t bind_port = BIND_PORT_RANGE_MIN; +const mod_network_nic_type_t mod_network_nic_type_nina; +static nina_obj_t nina_obj = {{(mp_obj_type_t *)&mod_network_nic_type_nina}, false, MOD_NETWORK_STA_IF}; + +STATIC mp_obj_t network_ninaw10_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 1, false); + + nina_obj.active = false; + if (n_args == 0) { + nina_obj.itf = MOD_NETWORK_STA_IF; + } else { + nina_obj.itf = mp_obj_get_int(args[0]); + } + + // Reset autobind port. + bind_port = BIND_PORT_RANGE_MIN; + + // Register with network module + mod_network_register_nic(MP_OBJ_FROM_PTR(&nina_obj)); + + return MP_OBJ_FROM_PTR(&nina_obj); +} + +STATIC mp_obj_t network_ninaw10_active(size_t n_args, const mp_obj_t *args) { + nina_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args == 2) { + bool active = mp_obj_is_true(args[1]); + if (active) { + int error = 0; + if ((error = nina_init()) != 0) { + mp_raise_msg_varg(&mp_type_OSError, + MP_ERROR_TEXT("Failed to initialize Nina-W10 module, error: %d\n"), error); + } + // check firmware version + uint8_t fw_ver[NINA_FW_VER_LEN]; + if (nina_fw_version(fw_ver) != 0) { + nina_deinit(); + mp_raise_msg_varg(&mp_type_OSError, + MP_ERROR_TEXT("Failed to read firmware version, error: %d\n"), error); + } + // Check fw version matches the driver. + if ((fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48) != NINA_FW_VER_MAJOR || + (fw_ver[NINA_FW_VER_MINOR_OFFS] - 48) != NINA_FW_VER_MINOR || + (fw_ver[NINA_FW_VER_PATCH_OFFS] - 48) != NINA_FW_VER_PATCH) { + mp_printf(&mp_plat_print, + "Warning: firmware version mismatch, expected %d.%d.%d found: %d.%d.%d\n", + NINA_FW_VER_MAJOR, NINA_FW_VER_MINOR, NINA_FW_VER_PATCH, + fw_ver[NINA_FW_VER_MAJOR_OFFS] - 48, + fw_ver[NINA_FW_VER_MINOR_OFFS] - 48, + fw_ver[NINA_FW_VER_PATCH_OFFS] - 48); + } + } else { + nina_deinit(); + } + self->active = active; + return mp_const_none; + } + return mp_obj_new_bool(self->active); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_active_obj, 1, 2, network_ninaw10_active); + +STATIC int nina_scan_callback(nina_scan_result_t *scan_result, void *arg) { + mp_obj_t scan_list = (mp_obj_t)arg; + + // Format MAC address + VSTR_FIXED(bssid_vstr, 18); + vstr_printf(&bssid_vstr, "%02X:%02X:%02X:%02X:%02X:%02X", + scan_result->bssid[0], scan_result->bssid[1], scan_result->bssid[2], + scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]); + + mp_obj_t ap[5] = { + mp_obj_new_int(scan_result->channel), + mp_obj_new_int(scan_result->rssi), + mp_obj_new_int(scan_result->security), + mp_obj_new_str(bssid_vstr.buf, bssid_vstr.len), + mp_obj_new_str(scan_result->ssid, strlen(scan_result->ssid)), + }; + + mp_obj_list_append(scan_list, mp_obj_new_tuple(MP_ARRAY_SIZE(ap), ap)); + + return 0; +} + +STATIC mp_obj_t network_ninaw10_scan(mp_obj_t self_in) { + mp_obj_t scan_list; + scan_list = mp_obj_new_list(0, NULL); + nina_scan(nina_scan_callback, scan_list, 10000); + return scan_list; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_scan_obj, network_ninaw10_scan); + +STATIC mp_obj_t network_ninaw10_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_essid, 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 = NINA_SEC_WPA_PSK} }, + { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + }; + + // parse args + nina_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + 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 ssid + const char *ssid = mp_obj_str_get_str(args[0].u_obj); + + if (strlen(ssid) == 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("SSID can't be empty!")); + } + + // get key and sec + const char *key = NULL; + mp_uint_t security = NINA_SEC_OPEN; + + if (args[1].u_obj != mp_const_none) { + key = mp_obj_str_get_str(args[1].u_obj); + security = args[2].u_int; + } + + if (security != NINA_SEC_OPEN && strlen(key) == 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Key can't be empty!")); + } + + if (self->itf == MOD_NETWORK_STA_IF) { + // Initialize WiFi in Station mode. + if (nina_connect(ssid, security, key, 0) != 0) { + mp_raise_msg_varg(&mp_type_OSError, + MP_ERROR_TEXT("could not connect to ssid=%s, sec=%d, key=%s\n"), ssid, security, key); + } + } else { + mp_uint_t channel = args[3].u_int; + + if (security != NINA_SEC_OPEN && security != NINA_SEC_WEP) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("AP mode supports WEP security only.")); + } + + // Initialize WiFi in AP mode. + if (nina_start_ap(ssid, security, key, channel) != 0) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("failed to start in AP mode")); + } + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_connect_obj, 1, network_ninaw10_connect); + +STATIC mp_obj_t network_ninaw10_disconnect(mp_obj_t self_in) { + nina_disconnect(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_disconnect_obj, network_ninaw10_disconnect); + +STATIC mp_obj_t network_ninaw10_isconnected(mp_obj_t self_in) { + return mp_obj_new_bool(nina_isconnected()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(network_ninaw10_isconnected_obj, network_ninaw10_isconnected); + +STATIC mp_obj_t network_ninaw10_ifconfig(size_t n_args, const mp_obj_t *args) { + nina_ifconfig_t ifconfig; + if (n_args == 1) { + // get ifconfig info + nina_ifconfig(&ifconfig, false); + mp_obj_t tuple[4] = { + netutils_format_ipv4_addr(ifconfig.ip_addr, NETUTILS_BIG), + netutils_format_ipv4_addr(ifconfig.subnet_addr, NETUTILS_BIG), + netutils_format_ipv4_addr(ifconfig.gateway_addr, NETUTILS_BIG), + netutils_format_ipv4_addr(ifconfig.dns_addr, NETUTILS_BIG), + }; + return mp_obj_new_tuple(4, tuple); + } else { + // set ifconfig info + mp_obj_t *items; + mp_obj_get_array_fixed_n(args[1], 4, &items); + netutils_parse_ipv4_addr(items[0], ifconfig.ip_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[1], ifconfig.subnet_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[2], ifconfig.gateway_addr, NETUTILS_BIG); + netutils_parse_ipv4_addr(items[3], ifconfig.dns_addr, NETUTILS_BIG); + nina_ifconfig(&ifconfig, true); + return mp_const_none; + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_ifconfig_obj, 1, 2, network_ninaw10_ifconfig); + +STATIC mp_obj_t network_ninaw10_config(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { + nina_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (kwargs->used == 0) { + // Get config value + if (n_args != 2) { + mp_raise_TypeError(MP_ERROR_TEXT("must query one param")); + } + + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_essid: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_str(netinfo.ssid, strlen(netinfo.ssid)); + } + case MP_QSTR_security: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_int(netinfo.security); + } + case MP_QSTR_mac: + case MP_QSTR_bssid: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_bytes(netinfo.bssid, 6); + } + case MP_QSTR_fw_version: { + uint8_t fwver[NINA_FW_VER_LEN]; + nina_fw_version(fwver); + return mp_obj_new_tuple(3, (mp_obj_t []) { + mp_obj_new_int(fwver[NINA_FW_VER_MAJOR_OFFS] - 48), + mp_obj_new_int(fwver[NINA_FW_VER_MINOR_OFFS] - 48), + mp_obj_new_int(fwver[NINA_FW_VER_PATCH_OFFS] - 48) + }); + } + default: + mp_raise_ValueError(MP_ERROR_TEXT("unknown config param")); + } + } else { + // Set config value(s) + // Not supported. + mp_raise_ValueError(MP_ERROR_TEXT("setting config values is not supported")); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(network_ninaw10_config_obj, 1, network_ninaw10_config); + +STATIC mp_obj_t network_ninaw10_status(size_t n_args, const mp_obj_t *args) { + nina_obj_t *self = MP_OBJ_TO_PTR(args[0]); + (void)self; + + if (n_args == 1) { + // no arguments: return link status + return mp_obj_new_bool(nina_isconnected()); + } + + // Query parameter. + switch (mp_obj_str_get_qstr(args[1])) { + case MP_QSTR_rssi: { + nina_netinfo_t netinfo; + nina_netinfo(&netinfo); + return mp_obj_new_int(netinfo.rssi); + } + case MP_QSTR_stations: { + if (self->itf != MOD_NETWORK_AP_IF) { + mp_raise_ValueError(MP_ERROR_TEXT("AP required")); + } + uint32_t sta_ip = 0; + mp_obj_t sta_list = mp_obj_new_list(0, NULL); + if (nina_connected_sta(&sta_ip) == 0) { + mp_obj_list_append(sta_list, + netutils_format_inet_addr((uint8_t *)&sta_ip, 0, NETUTILS_BIG)); + } + return sta_list; + } + } + + mp_raise_ValueError(MP_ERROR_TEXT("unknown status param")); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_ninaw10_status_obj, 1, 2, network_ninaw10_status); + +STATIC int network_ninaw10_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) { + return nina_gethostbyname(name, out_ip); +} + +STATIC int network_ninaw10_socket_socket(mod_network_socket_obj_t *socket, int *_errno) { + uint8_t type; + + if (socket->domain != MOD_NETWORK_AF_INET) { + *_errno = MP_EAFNOSUPPORT; + return -1; + } + + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: + type = NINA_SOCKET_TYPE_TCP; + break; + + case MOD_NETWORK_SOCK_DGRAM: + type = NINA_SOCKET_TYPE_UDP; + break; + + default: + *_errno = MP_EINVAL; + return -1; + } + + // open socket + int fd = nina_socket_socket(type); + if (fd < 0) { + *_errno = fd; + return -1; + } + + // store state of this socket + socket->fileno = fd; + socket->timeout = 0; // blocking + socket->bound = false; + return 0; +} + +STATIC void network_ninaw10_socket_close(mod_network_socket_obj_t *socket) { + if (socket->fileno >= 0) { + nina_socket_close(socket->fileno); + socket->fileno = -1; // Mark socket FD as invalid + } +} + +STATIC int network_ninaw10_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + uint8_t type; + switch (socket->type) { + case MOD_NETWORK_SOCK_STREAM: + type = NINA_SOCKET_TYPE_TCP; + break; + + case MOD_NETWORK_SOCK_DGRAM: + type = NINA_SOCKET_TYPE_UDP; + break; + + default: + *_errno = MP_EINVAL; + return -1; + } + + int ret = nina_socket_bind(socket->fileno, ip, port, type); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + + // Mark socket as bound to avoid auto-binding. + socket->bound = true; + return 0; +} + +STATIC int network_ninaw10_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) { + int ret = nina_socket_listen(socket->fileno, backlog); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return 0; +} + +STATIC int network_ninaw10_socket_accept(mod_network_socket_obj_t *socket, + mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) { + int fd = 0; + // Call accept. + int ret = nina_socket_accept(socket->fileno, ip, (uint16_t *)port, &fd, socket->timeout); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + + // Set default socket timeout. + socket2->fileno = fd; + socket2->timeout = 0; + socket2->bound = false; + return 0; +} + +STATIC int network_ninaw10_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) { + int ret = nina_socket_connect(socket->fileno, ip, port, socket->timeout); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return 0; +} + +STATIC mp_uint_t network_ninaw10_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) { + int ret = nina_socket_send(socket->fileno, buf, len, socket->timeout); + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return 0; + } else if (ret < 0) { + // Close the socket on any other errors. + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC mp_uint_t network_ninaw10_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) { + int ret = nina_socket_recv(socket->fileno, buf, len, socket->timeout); + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return 0; + } else if (ret < 0) { + // Close the socket on any other errors. + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC mp_uint_t network_ninaw10_socket_auto_bind(mod_network_socket_obj_t *socket, int *_errno) { + if (socket->bound == false) { + if (network_ninaw10_socket_bind(socket, NULL, bind_port, _errno) != 0) { + return -1; + } + bind_port++; + bind_port = MIN(MAX(bind_port, BIND_PORT_RANGE_MIN), BIND_PORT_RANGE_MAX); + } + return 0; +} + +STATIC mp_uint_t network_ninaw10_socket_sendto(mod_network_socket_obj_t *socket, + const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + // Auto-bind the socket first if the socket is unbound. + if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) { + return -1; + } + + int ret = nina_socket_sendto(socket->fileno, buf, len, ip, port, socket->timeout); + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return 0; + } else if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC mp_uint_t network_ninaw10_socket_recvfrom(mod_network_socket_obj_t *socket, + byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + // Auto-bind the socket first if the socket is unbound. + if (network_ninaw10_socket_auto_bind(socket, _errno) != 0) { + return -1; + } + + int ret = nina_socket_recvfrom(socket->fileno, buf, len, ip, (uint16_t *)port, socket->timeout); + if (ret == NINA_ERROR_TIMEOUT) { + // The socket is Not closed on timeout when calling functions that accept a timeout. + *_errno = MP_ETIMEDOUT; + return 0; + } else if (ret < 0) { + // Close the socket on any other errors. + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return ret; +} + +STATIC int network_ninaw10_socket_setsockopt(mod_network_socket_obj_t *socket, mp_uint_t + level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { + int ret = nina_socket_setsockopt(socket->fileno, level, opt, optval, optlen); + if (ret < 0) { + *_errno = ret; + network_ninaw10_socket_close(socket); + return -1; + } + return 0; +} + +STATIC int network_ninaw10_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) { + if (timeout_ms == UINT32_MAX) { + // no timeout is given, set the socket to blocking mode. + timeout_ms = 0; + } + socket->timeout = timeout_ms; + return 0; +} + +STATIC int network_ninaw10_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) { + *_errno = MP_EIO; + return -1; +} + +static const mp_rom_map_elem_t nina_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&network_ninaw10_active_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&network_ninaw10_scan_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&network_ninaw10_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&network_ninaw10_disconnect_obj) }, + { MP_ROM_QSTR(MP_QSTR_isconnected), MP_ROM_PTR(&network_ninaw10_isconnected_obj) }, + { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&network_ninaw10_ifconfig_obj) }, + { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_ninaw10_config_obj) }, + { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_ninaw10_status_obj) }, + + // Network is not secured. + { MP_ROM_QSTR(MP_QSTR_OPEN), MP_ROM_INT(NINA_SEC_OPEN) }, + // Security type WEP (40 or 104). + { MP_ROM_QSTR(MP_QSTR_WEP), MP_ROM_INT(NINA_SEC_WEP) }, + // Network secured with WPA/WPA2 personal(PSK). + { MP_ROM_QSTR(MP_QSTR_WPA_PSK), MP_ROM_INT(NINA_SEC_WPA_PSK) }, +}; + +static MP_DEFINE_CONST_DICT(nina_locals_dict, nina_locals_dict_table); + +const mod_network_nic_type_t mod_network_nic_type_nina = { + .base = { + { &mp_type_type }, + .name = MP_QSTR_nina, + .make_new = network_ninaw10_make_new, + .locals_dict = (mp_obj_t)&nina_locals_dict, + }, + .gethostbyname = network_ninaw10_gethostbyname, + .socket = network_ninaw10_socket_socket, + .close = network_ninaw10_socket_close, + .bind = network_ninaw10_socket_bind, + .listen = network_ninaw10_socket_listen, + .accept = network_ninaw10_socket_accept, + .connect = network_ninaw10_socket_connect, + .send = network_ninaw10_socket_send, + .recv = network_ninaw10_socket_recv, + .sendto = network_ninaw10_socket_sendto, + .recvfrom = network_ninaw10_socket_recvfrom, + .setsockopt = network_ninaw10_socket_setsockopt, + .settimeout = network_ninaw10_socket_settimeout, + .ioctl = network_ninaw10_socket_ioctl, +}; + +#endif // #if MICROPY_PY_BLUETOOTH && MICROPY_PY_NETWORK_NINAW10 |
