summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--stmhal/Makefile4
-rw-r--r--stmhal/modcc3k.c657
-rw-r--r--stmhal/modnetwork.c38
-rw-r--r--stmhal/modnetwork.h37
-rw-r--r--stmhal/modnwcc3k.c618
-rw-r--r--stmhal/modnwwiznet5k.c (renamed from stmhal/modwiznet5k.c)459
-rw-r--r--stmhal/modusocket.c363
-rw-r--r--stmhal/qstrdefsport.h52
8 files changed, 1269 insertions, 959 deletions
diff --git a/stmhal/Makefile b/stmhal/Makefile
index abf78ee8da..367cebd152 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -196,7 +196,7 @@ ifeq ($(MICROPY_PY_WIZNET5K),1)
WIZNET5K_DIR=drivers/wiznet5k
INC += -I$(TOP)/$(WIZNET5K_DIR)
CFLAGS_MOD += -DMICROPY_PY_WIZNET5K=1
-SRC_MOD += modwiznet5k.c
+SRC_MOD += modnwwiznet5k.c
SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\
ethernet/w5200/w5200.c \
ethernet/wizchip_conf.c \
@@ -210,7 +210,7 @@ ifeq ($(MICROPY_PY_CC3K),1)
CC3000_DIR=drivers/cc3000
INC += -I$(TOP)/$(CC3000_DIR)/inc
CFLAGS_MOD += -DMICROPY_PY_CC3K=1
-SRC_MOD += modcc3k.c
+SRC_MOD += modnwcc3k.c
SRC_MOD += $(addprefix $(CC3000_DIR)/src/,\
cc3000_common.c \
evnt_handler.c \
diff --git a/stmhal/modcc3k.c b/stmhal/modcc3k.c
deleted file mode 100644
index 5eab86101b..0000000000
--- a/stmhal/modcc3k.c
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * 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.
- */
-
-// We can't include stdio.h because it defines _types_fd_set, but we
-// need to use the CC3000 version of this type.
-
-#include <std.h>
-#include <string.h>
-#include <stdarg.h>
-#include <errno.h>
-
-// CC3000 defines its own ENOBUFS (different to standard one!)
-#undef ENOBUFS
-
-#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 "stream.h"
-#include "runtime.h"
-#include "modnetwork.h"
-#include "pin.h"
-#include "genhdr/pins.h"
-#include "spi.h"
-#include "pybioctl.h"
-
-#include "hci.h"
-#include "socket.h"
-#include "inet_ntop.h"
-#include "inet_pton.h"
-#include "ccspi.h"
-#include "wlan.h"
-#include "nvmem.h"
-#include "netapp.h"
-#include "patch_prog.h"
-
-/// \moduleref network
-
-int CC3000_EXPORT(errno); // for cc3000 driver
-
-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;
-STATIC volatile bool ip_obtained = false;
-
-STATIC int cc3k_get_fd_closed_state(int fd) {
- return fd_closed_state & (1 << fd);
-}
-
-STATIC void cc3k_set_fd_closed_state(int fd) {
- fd_closed_state |= 1 << fd;
-}
-
-STATIC void cc3k_reset_fd_closed_state(int fd) {
- fd_closed_state &= ~(1 << fd);
-}
-
-STATIC void cc3k_callback(long event_type, char *data, unsigned char length) {
- switch (event_type) {
- case HCI_EVNT_WLAN_UNSOL_CONNECT:
- wlan_connected = true;
- break;
- case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
- // link down
- wlan_connected = false;
- ip_obtained = false;
- break;
- case HCI_EVNT_WLAN_UNSOL_DHCP:
- ip_obtained = true;
- break;
- case HCI_EVNT_BSD_TCP_CLOSE_WAIT:
- // mark socket for closure
- cc3k_set_fd_closed_state(data[0]);
- break;
- }
-}
-
-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 (CC3000_EXPORT(gethostbyname)((char*)name, len, &ip) < 0) {
- return CC3000_EXPORT(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
-
-/// \class CC3k - driver for CC3000 Wifi modules
-
-typedef struct _cc3k_obj_t {
- mp_obj_base_t base;
-} cc3k_obj_t;
-
-/// \classmethod \constructor(spi, pin_cs, pin_en, pin_irq)
-/// Initialise the CC3000 using the given SPI bus and pins and return a CC3k object.
-//
-// Note: pins were originally hard-coded to:
-// PYBv1.0: init(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
-// [SPI on Y position; Y6=B13=SCK, Y7=B14=MISO, Y8=B15=MOSI]
-//
-// STM32F4DISC: init(pyb.SPI(2), pyb.Pin.cpu.A15, pyb.Pin.cpu.B10, pyb.Pin.cpu.B11)
-STATIC mp_obj_t cc3k_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, 4, 4, false);
-
- // set the pins to use
- SpiInit(
- spi_get_handle(args[0]),
- pin_find(args[1]),
- pin_find(args[2]),
- pin_find(args[3])
- );
-
- // initialize and start the module
- wlan_init(cc3k_callback, NULL, NULL, NULL,
- ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin);
-
- if (wlan_start(0) != 0) {
- nlr_raise(mp_obj_new_exception_msg(
- &mp_type_OSError, "Failed to init wlan module"));
- }
-
- // set connection policy. this should be called explicitly by the user
- // wlan_ioctl_set_connection_policy(0, 0, 0);
-
- // Mask out all non-required events from the CC3000
- wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE|
- HCI_EVNT_WLAN_UNSOL_INIT|
- HCI_EVNT_WLAN_ASYNC_PING_REPORT|
- HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE);
-
- cc3k_obj_t *cc3k = m_new_obj(cc3k_obj_t);
- cc3k->base.type = (mp_obj_type_t*)&mod_network_nic_type_cc3k;
-
- // register with network module
- mod_network_register_nic(cc3k);
-
- return cc3k;
-}
-
-/// \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} },
- };
-
- // 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 ssid
- mp_uint_t ssid_len;
- const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len);
-
- // get key and sec
- 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
- 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) {
- 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, 1, cc3k_connect);
-
-STATIC mp_obj_t cc3k_disconnect(mp_obj_t self_in) {
- int ret = wlan_disconnect();
- return mp_obj_new_int(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_disconnect_obj, cc3k_disconnect);
-
-STATIC mp_obj_t cc3k_is_connected(mp_obj_t self_in) {
- if (wlan_connected && ip_obtained) {
- return mp_const_true;
- }
- return mp_const_false;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_is_connected_obj, cc3k_is_connected);
-
-STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) {
- tNetappIpconfigRetArgs ipconfig={{0}};
-
- uint8_t *ip = &ipconfig.aucIP[0];
- uint8_t *mask= &ipconfig.aucSubnetMask[0];
- uint8_t *gw= &ipconfig.aucDefaultGateway[0];
- uint8_t *dhcp= &ipconfig.aucDHCPServer[0];
- uint8_t *dns= &ipconfig.aucDNSServer[0];
- uint8_t *mac= &ipconfig.uaMacAddr[0];
- uint8_t *ssid= &ipconfig.uaSSID[0];
-
- netapp_ipconfig(&ipconfig);
-
- printf ("IP:%d.%d.%d.%d\n" \
- "Mask:%d.%d.%d.%d\n"\
- "GW:%d.%d.%d.%d\n" \
- "DHCP:%d.%d.%d.%d\n"\
- "DNS:%d.%d.%d.%d\n" \
- "MAC:%02X:%02X:%02X:%02X:%02X:%02X\n"\
- "SSID: %s\n",
- ip[3], ip[2], ip[1], ip[0],
- mask[3], mask[2], mask[1], mask[0],
- gw[3], gw[2], gw[1], gw[0],
- dhcp[3], dhcp[2], dhcp[1], dhcp[0],
- dns[3], dns[2], dns[1], dns[0],
- mac[5], mac[4], mac[3], mac[2], mac[1], mac[0], ssid);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_ifconfig_obj, cc3k_ifconfig);
-
-STATIC mp_obj_t cc3k_patch_version(mp_obj_t self_in) {
- uint8_t pver[2];
- mp_obj_tuple_t *t_pver;
-
- nvmem_read_sp_version(pver);
- t_pver = mp_obj_new_tuple(2, NULL);
- t_pver->items[0] = mp_obj_new_int(pver[0]);
- t_pver->items[1] = mp_obj_new_int(pver[1]);
- return t_pver;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_patch_version_obj, cc3k_patch_version);
-
-STATIC mp_obj_t cc3k_patch_program(mp_obj_t self_in, mp_obj_t key_in) {
- const char *key = mp_obj_str_get_str(key_in);
- if (key[0] == 'p' && key[1] == 'g' && key[2] == 'm' && key[3] == '\0') {
- patch_prog_start();
- } else {
- printf("please pass 'pgm' as argument in order to program\n");
- }
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_patch_program_obj, cc3k_patch_program);
-
-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 },
- { MP_OBJ_NEW_QSTR(MP_QSTR_is_connected), (mp_obj_t)&cc3k_is_connected_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&cc3k_ifconfig_obj },
- { 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 },
-
- // 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) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(cc3k_locals_dict, cc3k_locals_dict_table);
-
-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,
-};
-
-/******************************************************************************/
-// Micro Python bindings; CC3k socket class
-
-#define MAX_ADDRSTRLEN (128)
-#define MAX_RX_PACKET (CC3000_RX_BUFFER_SIZE-CC3000_MINIMAL_RX_SIZE-1)
-#define MAX_TX_PACKET (CC3000_TX_BUFFER_SIZE-CC3000_MINIMAL_TX_SIZE-1)
-
-typedef struct _cc3k_socket_obj_t {
- mp_obj_base_t base;
- int fd;
-} cc3k_socket_obj_t;
-
-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;
-
- // open socket
- s->fd = CC3000_EXPORT(socket)(family, type, protocol);
- if (s->fd < 0) {
- m_del_obj(cc3k_socket_obj_t, s);
- *_errno = CC3000_EXPORT(errno);
- return MP_OBJ_NULL;
- }
-
- // clear socket state
- cc3k_reset_fd_closed_state(s->fd);
-
- return s;
-}
-
-STATIC void cc3k_socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
- cc3k_socket_obj_t *self = self_in;
- printf("<CC3k.socket fd=%d>", self->fd);
-}
-
-STATIC mp_obj_t cc3k_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
- cc3k_socket_obj_t *self = self_in;
-
- if (cc3k_get_fd_closed_state(self->fd)) {
- CC3000_EXPORT(closesocket)(self->fd);
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE)));
- }
-
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
-
- // CC3K does not handle fragmentation, and will overflow,
- // split the packet into smaller ones and send them out.
- mp_int_t bytes = 0;
- while (bytes < bufinfo.len) {
- int n = MIN((bufinfo.len - bytes), MAX_TX_PACKET);
- n = CC3000_EXPORT(send)(self->fd, (uint8_t*)bufinfo.buf + bytes, n, 0);
- if (n <= 0) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(CC3000_EXPORT(errno))));
- }
- bytes += n;
- }
-
- return MP_OBJ_NEW_SMALL_INT(bytes);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_send_obj, cc3k_socket_send);
-
-STATIC mp_obj_t cc3k_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
- cc3k_socket_obj_t *self = self_in;
-
- if (cc3k_get_fd_closed_state(self->fd)) {
- CC3000_EXPORT(closesocket)(self->fd);
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE)));
- }
-
- // recv upto MAX_RX_PACKET
- mp_int_t len = mp_obj_get_int(len_in);
- len = MIN(len, MAX_RX_PACKET);
-
- byte *buf;
- mp_obj_t ret_obj = mp_obj_str_builder_start(&mp_type_bytes, len, &buf);
- len = CC3000_EXPORT(recv)(self->fd, buf, len, 0);
- if (len == 0) {
- return mp_const_empty_bytes;
- } else if (len < 0) {
- nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(CC3000_EXPORT(errno))));
- } else {
- return mp_obj_str_builder_end_with_len(ret_obj, len);
- }
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_recv_obj, cc3k_socket_recv);
-
-STATIC mp_obj_t cc3k_socket_bind(mp_obj_t self_in, mp_obj_t addr_obj) {
- cc3k_socket_obj_t *self = self_in;
-
- mp_obj_t *addr;
- mp_obj_get_array_fixed_n(addr_obj, 2, &addr);
-
- // fill sockaddr struct
- int port = mp_obj_get_int(addr[1]);
- sockaddr_in addr_in = {
- .sin_family = AF_INET,
- .sin_port = htons(port),
- .sin_addr.s_addr = 0,// INADDR_ANY
- .sin_zero = {0}
- };
-
- const char *host = mp_obj_str_get_str(addr[0]);
- if (strlen(host) && !inet_pton(AF_INET, host, &addr_in.sin_addr.s_addr)) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "invalid IP address"));
- }
-
- // bind socket
- if (CC3000_EXPORT(bind)(self->fd, (sockaddr*) &addr_in, sizeof(sockaddr_in)) < 0) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "bind failed"));
- }
- return mp_const_true;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_bind_obj, cc3k_socket_bind);
-
-STATIC mp_obj_t cc3k_socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
- cc3k_socket_obj_t *self = self_in;
- if (CC3000_EXPORT(listen)(self->fd, mp_obj_get_int(backlog)) < 0) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "listen failed"));
- }
-
- return mp_const_true;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_listen_obj, cc3k_socket_listen);
-
-STATIC mp_obj_t cc3k_socket_accept(mp_obj_t self_in) {
- cc3k_socket_obj_t *self = self_in;
- int fd;
-
- sockaddr addr;
- socklen_t addr_len = sizeof(sockaddr);
-
- // accept incoming connection
- if ((fd = CC3000_EXPORT(accept)(self->fd, &addr, &addr_len)) < 0) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "accept failed"));
- }
-
- // clear socket state
- cc3k_reset_fd_closed_state(fd);
-
- // create new socket object
- cc3k_socket_obj_t *socket_obj = m_new_obj_with_finaliser(cc3k_socket_obj_t);
- socket_obj->base.type = (mp_obj_t)&cc3k_socket_type;
- socket_obj->fd = fd;
-
- char buf[MAX_ADDRSTRLEN]={0};
- if (inet_ntop(addr.sa_family,
- &(((sockaddr_in*)&addr)->sin_addr), buf, MAX_ADDRSTRLEN) == NULL) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "invalid IP address"));
- }
-
- mp_obj_tuple_t *cli = mp_obj_new_tuple(2, NULL);
- mp_obj_tuple_t *cli_addr = mp_obj_new_tuple(2, NULL);
-
- cli->items[0] = socket_obj;
- cli->items[1] = cli_addr;
- cli_addr->items[0] = mp_obj_new_str(buf, strlen(buf), false);
- cli_addr->items[1] = mp_obj_new_int(((sockaddr_in*)&addr)->sin_port);
-
- return cli;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_socket_accept_obj, cc3k_socket_accept);
-
-STATIC mp_obj_t cc3k_socket_connect(mp_obj_t self_in, mp_obj_t addr_obj) {
- cc3k_socket_obj_t *self = self_in;
-
- mp_obj_t *addr;
- mp_obj_get_array_fixed_n(addr_obj, 2, &addr);
-
- // fill sockaddr struct
- int port = mp_obj_get_int(addr[1]);
- sockaddr_in addr_in = {
- .sin_family = AF_INET,
- .sin_port = htons(port),
- .sin_addr.s_addr = 0, // to be filled below using inet_pton
- .sin_zero = {0}
- };
-
- const char *host = mp_obj_str_get_str(addr[0]);
- if (!inet_pton(AF_INET, host, &addr_in.sin_addr.s_addr)) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "invalid IP address"));
- }
-
- //printf("doing connect: fd=%d, sockaddr=(%d, %d, %lu)\n", self->fd, addr_in.sin_family, addr_in.sin_port, addr_in.sin_addr.s_addr);
-
- int ret = CC3000_EXPORT(connect)(self->fd, (sockaddr*)&addr_in, sizeof(sockaddr_in));
- if (ret != 0) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "[Errno %d] connect failed", ret));
- }
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_connect_obj, cc3k_socket_connect);
-
-STATIC mp_obj_t cc3k_socket_settimeout(mp_obj_t self_in, mp_obj_t timeout) {
- cc3k_socket_obj_t *self = self_in;
- int optval = mp_obj_get_int(timeout);
- socklen_t optlen = sizeof(optval);
-
- if (CC3000_EXPORT(setsockopt)(self->fd, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &optval, optlen) != 0) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "setsockopt failed"));
- }
-
- return mp_const_true;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_settimeout_obj, cc3k_socket_settimeout);
-
-STATIC mp_obj_t cc3k_socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
- cc3k_socket_obj_t *self = self_in;
- int optval;
- socklen_t optlen = sizeof(optval);
-
- if (mp_obj_get_int(blocking)) {
- optval = SOCK_OFF; // Enable non-blocking
- } else {
- optval = SOCK_ON;
- }
-
- if (CC3000_EXPORT(setsockopt)(self->fd, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen) != 0 ||
- CC3000_EXPORT(setsockopt)(self->fd, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen) != 0 ) {
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "setsockopt failed"));
- }
-
- return mp_const_true;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_socket_setblocking_obj, cc3k_socket_setblocking);
-
-STATIC mp_obj_t cc3k_socket_close(mp_obj_t self_in) {
- cc3k_socket_obj_t *self = self_in;
- CC3000_EXPORT(closesocket)(self->fd);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_socket_close_obj, cc3k_socket_close);
-
-STATIC const mp_map_elem_t cc3k_socket_locals_dict_table[] = {
- { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&cc3k_socket_send_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&cc3k_socket_recv_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&cc3k_socket_bind_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&cc3k_socket_listen_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&cc3k_socket_accept_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&cc3k_socket_connect_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&cc3k_socket_settimeout_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&cc3k_socket_setblocking_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&cc3k_socket_close_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&cc3k_socket_close_obj },
-};
-
-STATIC MP_DEFINE_CONST_DICT(cc3k_socket_locals_dict, cc3k_socket_locals_dict_table);
-
-mp_uint_t cc3k_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
- cc3k_socket_obj_t *self = self_in;
- mp_uint_t ret;
- if (request == MP_IOCTL_POLL) {
- mp_uint_t flags = arg;
- ret = 0;
- int fd = self->fd;
-
- // init fds
- fd_set rfds, wfds, xfds;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
-
- // set fds if needed
- if (flags & MP_IOCTL_POLL_RD) {
- FD_SET(fd, &rfds);
-
- // A socked that just closed is available for reading. A call to
- // recv() returns 0 which is consistent with BSD.
- if (cc3k_get_fd_closed_state(fd)) {
- ret |= MP_IOCTL_POLL_RD;
- }
- }
- if (flags & MP_IOCTL_POLL_WR) {
- FD_SET(fd, &wfds);
- }
- if (flags & MP_IOCTL_POLL_HUP) {
- FD_SET(fd, &xfds);
- }
-
- // call cc3000 select with minimum timeout
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 1;
- int nfds = CC3000_EXPORT(select)(fd + 1, &rfds, &wfds, &xfds, &tv);
-
- // check for error
- if (nfds == -1) {
- *errcode = CC3000_EXPORT(errno);
- return -1;
- }
-
- // check return of select
- if (FD_ISSET(fd, &rfds)) {
- ret |= MP_IOCTL_POLL_RD;
- }
- if (FD_ISSET(fd, &wfds)) {
- ret |= MP_IOCTL_POLL_WR;
- }
- if (FD_ISSET(fd, &xfds)) {
- ret |= MP_IOCTL_POLL_HUP;
- }
- } else {
- *errcode = EINVAL;
- ret = -1;
- }
- return ret;
-}
-
-STATIC const mp_stream_p_t cc3k_socket_stream_p = {
- .ioctl = cc3k_ioctl,
- .is_text = false,
-};
-
-STATIC const mp_obj_type_t cc3k_socket_type = {
- { &mp_type_type },
- .name = MP_QSTR_socket,
- .print = cc3k_socket_print,
- .stream_p = &cc3k_socket_stream_p,
- .locals_dict = (mp_obj_t)&cc3k_socket_locals_dict,
-};
diff --git a/stmhal/modnetwork.c b/stmhal/modnetwork.c
index fd3fee9284..e4d0fcdf9e 100644
--- a/stmhal/modnetwork.c
+++ b/stmhal/modnetwork.c
@@ -61,6 +61,18 @@ void mod_network_register_nic(mp_obj_t nic) {
mp_obj_list_append(&mod_network_nic_list, nic);
}
+mp_obj_t mod_network_find_nic(const uint8_t *ip) {
+ // find a NIC that is suited to given IP address
+ for (mp_uint_t i = 0; i < mod_network_nic_list.len; i++) {
+ mp_obj_t nic = mod_network_nic_list.items[i];
+ // TODO check IP suitability here
+ //mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic);
+ return nic;
+ }
+
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
+}
+
STATIC mp_obj_t network_route(void) {
return &mod_network_nic_list;
}
@@ -70,10 +82,10 @@ 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 },
+ { 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 },
+ { 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 },
@@ -90,18 +102,32 @@ const mp_obj_module_t mp_module_network = {
/******************************************************************************/
// Miscellaneous helpers
+void mod_network_convert_ipv4_endianness(uint8_t *ip) {
+ uint8_t ip0 = ip[0]; ip[0] = ip[3]; ip[3] = ip0;
+ uint8_t ip1 = ip[1]; ip[1] = ip[2]; ip[2] = ip1;
+}
+
+// Takes an address of the form '192.168.0.1' and converts it to network format
+// in out_ip (big endian, so the 192 is the first byte).
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);
+ mp_uint_t addr_len;
+ const char *addr_str = mp_obj_str_get_data(addr_in, &addr_len);
+ if (addr_len == 0) {
+ // special case of no address given
+ memset(out_ip, 0, MOD_NETWORK_IPADDR_BUF_SIZE);
+ return;
+ }
const char *s = addr_str;
+ const char *s_top = addr_str + addr_len;
for (mp_uint_t i = 0;; i++) {
mp_uint_t val = 0;
- for (; *s && *s != '.'; s++) {
+ for (; s < s_top && *s != '.'; s++) {
val = val * 10 + *s - '0';
}
out_ip[i] = val;
- if (i == 3 && *s == '\0') {
+ if (i == 3 && s == s_top) {
return;
- } else if (i < 3 && *s == '.') {
+ } else if (i < 3 && s < s_top && *s == '.') {
s++;
} else {
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid IP address"));
diff --git a/stmhal/modnetwork.h b/stmhal/modnetwork.h
index ed31a602f2..8e23f877f2 100644
--- a/stmhal/modnetwork.h
+++ b/stmhal/modnetwork.h
@@ -33,22 +33,55 @@
#define MOD_NETWORK_SOCK_DGRAM (2)
#define MOD_NETWORK_SOCK_RAW (3)
+struct _mod_network_socket_obj_t;
+
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);
+ // API for non-socket operations
int (*gethostbyname)(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *ip_out);
+
+ // API for socket operations; return -1 on error
+ int (*socket)(struct _mod_network_socket_obj_t *socket, int *_errno);
+ void (*close)(struct _mod_network_socket_obj_t *socket);
+ int (*bind)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno);
+ int (*listen)(struct _mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno);
+ int (*accept)(struct _mod_network_socket_obj_t *socket, struct _mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno);
+ int (*connect)(struct _mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno);
+ mp_uint_t (*send)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno);
+ mp_uint_t (*recv)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno);
+ mp_uint_t (*sendto)(struct _mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno);
+ mp_uint_t (*recvfrom)(struct _mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno);
+ int (*setsockopt)(struct _mod_network_socket_obj_t *socket, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno);
+ int (*settimeout)(struct _mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno);
+ int (*ioctl)(struct _mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
} mod_network_nic_type_t;
+typedef struct _mod_network_socket_obj_t {
+ mp_obj_base_t base;
+ mp_obj_t nic;
+ mod_network_nic_type_t *nic_type;
+ union {
+ struct {
+ uint8_t domain;
+ uint8_t type;
+ int8_t fileno;
+ } u_param;
+ mp_uint_t u_state;
+ };
+} mod_network_socket_obj_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);
+mp_obj_t mod_network_find_nic(const uint8_t *ip);
+void mod_network_convert_ipv4_endianness(uint8_t *ip);
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_ipv4_addr(uint8_t *ip);
mp_obj_t mod_network_format_inet_addr(uint8_t *ip, mp_uint_t port);
diff --git a/stmhal/modnwcc3k.c b/stmhal/modnwcc3k.c
new file mode 100644
index 0000000000..41358a06cb
--- /dev/null
+++ b/stmhal/modnwcc3k.c
@@ -0,0 +1,618 @@
+/*
+ * 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.
+ */
+
+// We can't include stdio.h because it defines _types_fd_set, but we
+// need to use the CC3000 version of this type.
+
+#include <std.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+// CC3000 defines its own ENOBUFS (different to standard one!)
+#undef ENOBUFS
+
+#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 "stream.h"
+#include "runtime.h"
+#include "modnetwork.h"
+#include "pin.h"
+#include "genhdr/pins.h"
+#include "spi.h"
+#include "pybioctl.h"
+
+#include "hci.h"
+#include "socket.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "ccspi.h"
+#include "wlan.h"
+#include "nvmem.h"
+#include "netapp.h"
+#include "patch_prog.h"
+
+#define MAX_ADDRSTRLEN (128)
+#define MAX_RX_PACKET (CC3000_RX_BUFFER_SIZE-CC3000_MINIMAL_RX_SIZE-1)
+#define MAX_TX_PACKET (CC3000_TX_BUFFER_SIZE-CC3000_MINIMAL_TX_SIZE-1)
+
+#define MAKE_SOCKADDR(addr, ip, port) \
+ sockaddr addr; \
+ addr.sa_family = AF_INET; \
+ addr.sa_data[0] = port >> 8; \
+ addr.sa_data[1] = port; \
+ addr.sa_data[2] = ip[0]; \
+ addr.sa_data[3] = ip[1]; \
+ addr.sa_data[4] = ip[2]; \
+ addr.sa_data[5] = ip[3];
+
+#define UNPACK_SOCKADDR(addr, ip, port) \
+ port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \
+ ip[0] = addr.sa_data[2]; \
+ ip[1] = addr.sa_data[3]; \
+ ip[2] = addr.sa_data[4]; \
+ ip[3] = addr.sa_data[5];
+
+STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno);
+
+int CC3000_EXPORT(errno); // for cc3000 driver
+
+STATIC volatile uint32_t fd_closed_state = 0;
+STATIC volatile bool wlan_connected = false;
+STATIC volatile bool ip_obtained = false;
+
+STATIC int cc3k_get_fd_closed_state(int fd) {
+ return fd_closed_state & (1 << fd);
+}
+
+STATIC void cc3k_set_fd_closed_state(int fd) {
+ fd_closed_state |= 1 << fd;
+}
+
+STATIC void cc3k_reset_fd_closed_state(int fd) {
+ fd_closed_state &= ~(1 << fd);
+}
+
+STATIC void cc3k_callback(long event_type, char *data, unsigned char length) {
+ switch (event_type) {
+ case HCI_EVNT_WLAN_UNSOL_CONNECT:
+ wlan_connected = true;
+ break;
+ case HCI_EVNT_WLAN_UNSOL_DISCONNECT:
+ // link down
+ wlan_connected = false;
+ ip_obtained = false;
+ break;
+ case HCI_EVNT_WLAN_UNSOL_DHCP:
+ ip_obtained = true;
+ break;
+ case HCI_EVNT_BSD_TCP_CLOSE_WAIT:
+ // mark socket for closure
+ cc3k_set_fd_closed_state(data[0]);
+ break;
+ }
+}
+
+STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
+ uint32_t ip;
+ // CC3000 gethostbyname is unreliable and usually returns -95 on first call
+ for (int retry = 5; CC3000_EXPORT(gethostbyname)((char*)name, len, &ip) < 0; retry--) {
+ if (retry == 0 || CC3000_EXPORT(errno) != -95) {
+ return CC3000_EXPORT(errno);
+ }
+ HAL_Delay(50);
+ }
+
+ 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;
+}
+
+STATIC int cc3k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
+ if (socket->u_param.domain != MOD_NETWORK_AF_INET) {
+ *_errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ mp_uint_t type;
+ switch (socket->u_param.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 -1;
+ }
+
+ // open socket
+ int fd = CC3000_EXPORT(socket)(AF_INET, type, 0);
+ if (fd < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ // clear socket state
+ cc3k_reset_fd_closed_state(fd);
+
+ // store state of this socket
+ socket->u_state = fd;
+
+ // make accept blocking by default
+ int optval = SOCK_OFF;
+ socklen_t optlen = sizeof(optval);
+ CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
+
+ return 0;
+}
+
+STATIC void cc3k_socket_close(mod_network_socket_obj_t *socket) {
+ CC3000_EXPORT(closesocket)(socket->u_state);
+}
+
+STATIC int cc3k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = CC3000_EXPORT(bind)(socket->u_state, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int cc3k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
+ int ret = CC3000_EXPORT(listen)(socket->u_state, backlog);
+ if (ret != 0) {
+ *_errno = ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int cc3k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
+ // accept incoming connection
+ int fd;
+ sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+ if ((fd = CC3000_EXPORT(accept)(socket->u_state, &addr, &addr_len)) < 0) {
+ if (fd == SOC_IN_PROGRESS) {
+ *_errno = EAGAIN;
+ } else {
+ *_errno = -fd;
+ }
+ return -1;
+ }
+
+ // clear socket state
+ cc3k_reset_fd_closed_state(fd);
+
+ // store state in new socket object
+ socket2->u_state = fd;
+
+ // return ip and port
+ // it seems CC3000 returns little endian for accept??
+ //UNPACK_SOCKADDR(addr, ip, *port);
+ *port = (addr.sa_data[1] << 8) | addr.sa_data[0];
+ ip[3] = addr.sa_data[2];
+ ip[2] = addr.sa_data[3];
+ ip[1] = addr.sa_data[4];
+ ip[0] = addr.sa_data[5];
+
+ return 0;
+}
+
+STATIC int cc3k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = CC3000_EXPORT(connect)(socket->u_state, &addr, sizeof(addr));
+ if (ret != 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ return 0;
+}
+
+STATIC mp_uint_t cc3k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
+ if (cc3k_get_fd_closed_state(socket->u_state)) {
+ CC3000_EXPORT(closesocket)(socket->u_state);
+ *_errno = EPIPE;
+ return -1;
+ }
+
+ // CC3K does not handle fragmentation, and will overflow,
+ // split the packet into smaller ones and send them out.
+ mp_int_t bytes = 0;
+ while (bytes < len) {
+ int n = MIN((len - bytes), MAX_TX_PACKET);
+ n = CC3000_EXPORT(send)(socket->u_state, (uint8_t*)buf + bytes, n, 0);
+ if (n <= 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ bytes += n;
+ }
+
+ return bytes;
+}
+
+STATIC mp_uint_t cc3k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
+ // check the socket is open
+ if (cc3k_get_fd_closed_state(socket->u_state)) {
+ // socket is closed, but CC3000 may have some data remaining in buffer, so check
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(socket->u_state, &rfds);
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ int nfds = CC3000_EXPORT(select)(socket->u_state + 1, &rfds, NULL, NULL, &tv);
+ if (nfds == -1 || !FD_ISSET(socket->u_state, &rfds)) {
+ // no data waiting, so close socket and return 0 data
+ CC3000_EXPORT(closesocket)(socket->u_state);
+ return 0;
+ }
+ }
+
+ // cap length at MAX_RX_PACKET
+ len = MIN(len, MAX_RX_PACKET);
+
+ // do the recv
+ int ret = CC3000_EXPORT(recv)(socket->u_state, buf, len, 0);
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ return ret;
+}
+
+STATIC mp_uint_t cc3k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+ MAKE_SOCKADDR(addr, ip, port)
+ int ret = CC3000_EXPORT(sendto)(socket->u_state, (byte*)buf, len, 0, (sockaddr*)&addr, sizeof(addr));
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t cc3k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+ sockaddr addr;
+ socklen_t addr_len = sizeof(addr);
+ mp_int_t ret = CC3000_EXPORT(recvfrom)(socket->u_state, buf, len, 0, &addr, &addr_len);
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ UNPACK_SOCKADDR(addr, ip, *port);
+ return ret;
+}
+
+STATIC int cc3k_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 = CC3000_EXPORT(setsockopt)(socket->u_state, level, opt, optval, optlen);
+ if (ret < 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int cc3k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
+ int ret;
+ if (timeout_ms == 0 || timeout_ms == -1) {
+ int optval;
+ socklen_t optlen = sizeof(optval);
+ if (timeout_ms == 0) {
+ // set non-blocking mode
+ optval = SOCK_ON;
+ } else {
+ // set blocking mode
+ optval = SOCK_OFF;
+ }
+ ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen);
+ if (ret == 0) {
+ ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_ACCEPT_NONBLOCK, &optval, optlen);
+ }
+ } else {
+ // set timeout
+ socklen_t optlen = sizeof(timeout_ms);
+ ret = CC3000_EXPORT(setsockopt)(socket->u_state, SOL_SOCKET, SOCKOPT_RECV_TIMEOUT, &timeout_ms, optlen);
+ }
+
+ if (ret != 0) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+STATIC int cc3k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
+ mp_uint_t ret;
+ if (request == MP_IOCTL_POLL) {
+ mp_uint_t flags = arg;
+ ret = 0;
+ int fd = socket->u_state;
+
+ // init fds
+ fd_set rfds, wfds, xfds;
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&xfds);
+
+ // set fds if needed
+ if (flags & MP_IOCTL_POLL_RD) {
+ FD_SET(fd, &rfds);
+
+ // A socked that just closed is available for reading. A call to
+ // recv() returns 0 which is consistent with BSD.
+ if (cc3k_get_fd_closed_state(fd)) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ }
+ if (flags & MP_IOCTL_POLL_WR) {
+ FD_SET(fd, &wfds);
+ }
+ if (flags & MP_IOCTL_POLL_HUP) {
+ FD_SET(fd, &xfds);
+ }
+
+ // call cc3000 select with minimum timeout
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ int nfds = CC3000_EXPORT(select)(fd + 1, &rfds, &wfds, &xfds, &tv);
+
+ // check for error
+ if (nfds == -1) {
+ *_errno = CC3000_EXPORT(errno);
+ return -1;
+ }
+
+ // check return of select
+ if (FD_ISSET(fd, &rfds)) {
+ ret |= MP_IOCTL_POLL_RD;
+ }
+ if (FD_ISSET(fd, &wfds)) {
+ ret |= MP_IOCTL_POLL_WR;
+ }
+ if (FD_ISSET(fd, &xfds)) {
+ ret |= MP_IOCTL_POLL_HUP;
+ }
+ } else {
+ *_errno = EINVAL;
+ ret = -1;
+ }
+ return ret;
+}
+
+/******************************************************************************/
+// Micro Python bindings; CC3K class
+
+typedef struct _cc3k_obj_t {
+ mp_obj_base_t base;
+} cc3k_obj_t;
+
+// \classmethod \constructor(spi, pin_cs, pin_en, pin_irq)
+// Initialise the CC3000 using the given SPI bus and pins and return a CC3K object.
+//
+// Note: pins were originally hard-coded to:
+// PYBv1.0: init(pyb.SPI(2), pyb.Pin.board.Y5, pyb.Pin.board.Y4, pyb.Pin.board.Y3)
+// [SPI on Y position; Y6=B13=SCK, Y7=B14=MISO, Y8=B15=MOSI]
+//
+// STM32F4DISC: init(pyb.SPI(2), pyb.Pin.cpu.A15, pyb.Pin.cpu.B10, pyb.Pin.cpu.B11)
+STATIC mp_obj_t cc3k_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, 4, 4, false);
+
+ // set the pins to use
+ SpiInit(
+ spi_get_handle(args[0]),
+ pin_find(args[1]),
+ pin_find(args[2]),
+ pin_find(args[3])
+ );
+
+ // initialize and start the module
+ wlan_init(cc3k_callback, NULL, NULL, NULL,
+ ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin);
+
+ if (wlan_start(0) != 0) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "failed to init CC3000 module"));
+ }
+
+ // set connection policy. this should be called explicitly by the user
+ // wlan_ioctl_set_connection_policy(0, 0, 0);
+
+ // Mask out all non-required events from the CC3000
+ wlan_set_event_mask(HCI_EVNT_WLAN_KEEPALIVE|
+ HCI_EVNT_WLAN_UNSOL_INIT|
+ HCI_EVNT_WLAN_ASYNC_PING_REPORT|
+ HCI_EVNT_WLAN_ASYNC_SIMPLE_CONFIG_DONE);
+
+ cc3k_obj_t *cc3k = m_new_obj(cc3k_obj_t);
+ cc3k->base.type = (mp_obj_type_t*)&mod_network_nic_type_cc3k;
+
+ // register with network module
+ mod_network_register_nic(cc3k);
+
+ return cc3k;
+}
+
+// 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} },
+ };
+
+ // 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 ssid
+ mp_uint_t ssid_len;
+ const char *ssid = mp_obj_str_get_data(args[0].u_obj, &ssid_len);
+
+ // get key and sec
+ 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
+ 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) {
+ 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, 1, cc3k_connect);
+
+STATIC mp_obj_t cc3k_disconnect(mp_obj_t self_in) {
+ // should we check return value?
+ wlan_disconnect();
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_disconnect_obj, cc3k_disconnect);
+
+STATIC mp_obj_t cc3k_isconnected(mp_obj_t self_in) {
+ return MP_BOOL(wlan_connected && ip_obtained);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_isconnected_obj, cc3k_isconnected);
+
+STATIC mp_obj_t cc3k_ifconfig(mp_obj_t self_in) {
+ tNetappIpconfigRetArgs ipconfig;
+ netapp_ipconfig(&ipconfig);
+
+ // CC3000 returns little endian, but we want big endian
+ mod_network_convert_ipv4_endianness(ipconfig.aucIP);
+ mod_network_convert_ipv4_endianness(ipconfig.aucSubnetMask);
+ mod_network_convert_ipv4_endianness(ipconfig.aucDefaultGateway);
+ mod_network_convert_ipv4_endianness(ipconfig.aucDNSServer);
+ mod_network_convert_ipv4_endianness(ipconfig.aucDHCPServer);
+
+ // render MAC address
+ char mac_str[18];
+ const uint8_t *mac = ipconfig.uaMacAddr;
+ mp_uint_t mac_len = snprintf(mac_str, 18, "%02X:%02x:%02x:%02x:%02x:%02x", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]);
+
+ // create and return tuple with ifconfig info
+ mp_obj_t tuple[7] = {
+ mod_network_format_ipv4_addr(ipconfig.aucIP),
+ mod_network_format_ipv4_addr(ipconfig.aucSubnetMask),
+ mod_network_format_ipv4_addr(ipconfig.aucDefaultGateway),
+ mod_network_format_ipv4_addr(ipconfig.aucDNSServer),
+ mod_network_format_ipv4_addr(ipconfig.aucDHCPServer),
+ mp_obj_new_str(mac_str, mac_len, false),
+ mp_obj_new_str((const char*)ipconfig.uaSSID, strlen((const char*)ipconfig.uaSSID), false),
+ };
+ return mp_obj_new_tuple(MP_ARRAY_SIZE(tuple), tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_ifconfig_obj, cc3k_ifconfig);
+
+STATIC mp_obj_t cc3k_patch_version(mp_obj_t self_in) {
+ uint8_t pver[2];
+ mp_obj_tuple_t *t_pver;
+
+ nvmem_read_sp_version(pver);
+ t_pver = mp_obj_new_tuple(2, NULL);
+ t_pver->items[0] = mp_obj_new_int(pver[0]);
+ t_pver->items[1] = mp_obj_new_int(pver[1]);
+ return t_pver;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_patch_version_obj, cc3k_patch_version);
+
+STATIC mp_obj_t cc3k_patch_program(mp_obj_t self_in, mp_obj_t key_in) {
+ const char *key = mp_obj_str_get_str(key_in);
+ if (key[0] == 'p' && key[1] == 'g' && key[2] == 'm' && key[3] == '\0') {
+ patch_prog_start();
+ } else {
+ printf("pass 'pgm' as argument in order to program\n");
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_patch_program_obj, cc3k_patch_program);
+
+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 },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_isconnected), (mp_obj_t)&cc3k_isconnected_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ifconfig), (mp_obj_t)&cc3k_ifconfig_obj },
+ { 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 },
+
+ // 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) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(cc3k_locals_dict, cc3k_locals_dict_table);
+
+const mod_network_nic_type_t mod_network_nic_type_cc3k = {
+ .base = {
+ { &mp_type_type },
+ .name = MP_QSTR_CC3K,
+ .make_new = cc3k_make_new,
+ .locals_dict = (mp_obj_t)&cc3k_locals_dict,
+ },
+ .gethostbyname = cc3k_gethostbyname,
+ .socket = cc3k_socket_socket,
+ .close = cc3k_socket_close,
+ .bind = cc3k_socket_bind,
+ .listen = cc3k_socket_listen,
+ .accept = cc3k_socket_accept,
+ .connect = cc3k_socket_connect,
+ .send = cc3k_socket_send,
+ .recv = cc3k_socket_recv,
+ .sendto = cc3k_socket_sendto,
+ .recvfrom = cc3k_socket_recvfrom,
+ .setsockopt = cc3k_socket_setsockopt,
+ .settimeout = cc3k_socket_settimeout,
+ .ioctl = cc3k_socket_ioctl,
+};
diff --git a/stmhal/modwiznet5k.c b/stmhal/modnwwiznet5k.c
index e91bd502a7..4818ff9eb1 100644
--- a/stmhal/modwiznet5k.c
+++ b/stmhal/modnwwiznet5k.c
@@ -50,10 +50,6 @@
/// \moduleref network
-#define IPADDR_BUF_SIZE (4)
-
-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;
@@ -91,86 +87,242 @@ STATIC void wiz_spi_write(const uint8_t *buf, uint32_t len) {
(void)status;
}
-// Check the return value from Wiz socket calls:
-// - on error (<0) an exception is raised
-// - SOCK_OK or SOCK_BUSY does nothing
-// - anything positive does nothing
-STATIC void check_sock_return_value(int8_t ret) {
- // TODO convert Wiz errno's to POSIX ones
- if (ret < 0) {
- nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OSError, "socket error %d", ret));
+STATIC int wiznet5k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
+ uint8_t dns_ip[MOD_NETWORK_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;
}
}
-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) {
+STATIC int wiznet5k_socket_socket(mod_network_socket_obj_t *socket, int *_errno) {
+ if (socket->u_param.domain != MOD_NETWORK_AF_INET) {
*_errno = EAFNOSUPPORT;
- return MP_OBJ_NULL;
+ return -1;
}
- 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;
+ switch (socket->u_param.type) {
+ case MOD_NETWORK_SOCK_STREAM: socket->u_param.type = Sn_MR_TCP; break;
+ case MOD_NETWORK_SOCK_DGRAM: socket->u_param.type = Sn_MR_UDP; break;
+ default: *_errno = EINVAL; return -1;
}
- if (fileno < 0) {
+ if (socket->u_param.fileno == -1) {
// 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;
+ wiznet5k_obj.socket_used |= (1 << sn);
+ socket->u_param.fileno = sn;
break;
}
}
- if (fileno < 0) {
+ if (socket->u_param.fileno == -1) {
// too many open sockets
*_errno = EMFILE;
- return MP_OBJ_NULL;
+ return -1;
}
}
- return wiznet5k_socket_new(fileno, type);
+ // WIZNET does not have a concept of pure "open socket". You need to know
+ // if it's a server or client at the time of creation of the socket.
+ // So, we defer the open until we know what kind of socket we want.
+
+ // use "domain" to indicate that this socket has not yet been opened
+ socket->u_param.domain = 0;
+
+ return 0;
}
-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;
+STATIC void wiznet5k_socket_close(mod_network_socket_obj_t *socket) {
+ uint8_t sn = (uint8_t)socket->u_param.fileno;
+ if (sn < _WIZCHIP_SOCK_NUM_) {
+ wiznet5k_obj.socket_used &= ~(1 << sn);
+ WIZCHIP_EXPORT(close)(sn);
}
}
-/******************************************************************************/
-// Micro Python bindings
-/// \class WIZnet5k - driver for WIZnet5x00 Ethernet modules
-///
-/// This class allows you to control WIZnet5x00 Ethernet adaptors based on
-/// the W5200 and W5500 chipsets (only W5200 tested).
-///
-/// Example usage:
-///
-/// import wiznet5k
-/// w = wiznet5k.WIZnet5k()
-/// print(w.ipaddr())
-/// w.gethostbyname('micropython.org')
-/// s = w.socket()
-/// s.connect(('192.168.0.2', 8080))
-/// s.send('hello')
-/// print(s.recv(10))
-
-STATIC void wiznet5k_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
- print(env, "WIZnet5k()");
+STATIC int wiznet5k_socket_bind(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ // open the socket in server mode (if port != 0)
+ mp_int_t ret = WIZCHIP_EXPORT(socket)(socket->u_param.fileno, socket->u_param.type, port, 0);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+
+ // indicate that this socket has been opened
+ socket->u_param.domain = 1;
+
+ // success
+ return 0;
}
+STATIC int wiznet5k_socket_listen(mod_network_socket_obj_t *socket, mp_int_t backlog, int *_errno) {
+ mp_int_t ret = WIZCHIP_EXPORT(listen)(socket->u_param.fileno);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return 0;
+}
+
+STATIC int wiznet5k_socket_accept(mod_network_socket_obj_t *socket, mod_network_socket_obj_t *socket2, byte *ip, mp_uint_t *port, int *_errno) {
+ for (;;) {
+ int sr = getSn_SR((uint8_t)socket->u_param.fileno);
+ if (sr == SOCK_ESTABLISHED) {
+ socket2->u_param = socket->u_param;
+ // TODO need to populate this with the correct values
+ ip[0] = 0;
+ ip[1] = 0;
+ ip[2] = 0;
+ ip[3] = 0;
+ *port = getSn_PORT(socket2->u_param.fileno);
+
+ // WIZnet turns the listening socket into the client socket, so we
+ // need to re-bind and re-listen on another socket for the server.
+ // TODO handle errors, especially no-more-sockets error
+ socket->u_param.domain = MOD_NETWORK_AF_INET;
+ socket->u_param.fileno = -1;
+ int _errno2;
+ if (wiznet5k_socket_socket(socket, &_errno2) != 0) {
+ //printf("(bad resocket %d)\n", _errno2);
+ } else if (wiznet5k_socket_bind(socket, NULL, *port, &_errno2) != 0) {
+ //printf("(bad rebind %d)\n", _errno2);
+ } else if (wiznet5k_socket_listen(socket, 0, &_errno2) != 0) {
+ //printf("(bad relisten %d)\n", _errno2);
+ }
+
+ return 0;
+ }
+ if (sr == SOCK_CLOSED || sr == SOCK_CLOSE_WAIT) {
+ wiznet5k_socket_close(socket);
+ *_errno = ENOTCONN; // ??
+ return -1;
+ }
+ HAL_Delay(1);
+ }
+}
+
+STATIC int wiznet5k_socket_connect(mod_network_socket_obj_t *socket, byte *ip, mp_uint_t port, int *_errno) {
+ // use "bind" function to open the socket in client mode
+ if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) {
+ return -1;
+ }
+
+ // now connect
+ mp_int_t ret = WIZCHIP_EXPORT(connect)(socket->u_param.fileno, ip, port);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+
+ // success
+ return 0;
+}
+
+STATIC mp_uint_t wiznet5k_socket_send(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
+ mp_int_t ret = WIZCHIP_EXPORT(send)(socket->u_param.fileno, (byte*)buf, len);
+ // TODO convert Wiz errno's to POSIX ones
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t wiznet5k_socket_recv(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, int *_errno) {
+ mp_int_t ret = WIZCHIP_EXPORT(recv)(socket->u_param.fileno, buf, len);
+ // TODO convert Wiz errno's to POSIX ones
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t wiznet5k_socket_sendto(mod_network_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+ if (socket->u_param.domain == 0) {
+ // socket not opened; use "bind" function to open the socket in client mode
+ if (wiznet5k_socket_bind(socket, ip, 0, _errno) != 0) {
+ return -1;
+ }
+ }
+
+ mp_int_t ret = WIZCHIP_EXPORT(sendto)(socket->u_param.fileno, (byte*)buf, len, ip, port);
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC mp_uint_t wiznet5k_socket_recvfrom(mod_network_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
+ uint16_t port2;
+ mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(socket->u_param.fileno, buf, len, ip, &port2);
+ *port = port2;
+ if (ret < 0) {
+ wiznet5k_socket_close(socket);
+ *_errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+STATIC int wiznet5k_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) {
+ // TODO
+ *_errno = EINVAL;
+ return -1;
+}
+
+STATIC int wiznet5k_socket_settimeout(mod_network_socket_obj_t *socket, mp_uint_t timeout_ms, int *_errno) {
+ // TODO
+ *_errno = EINVAL;
+ return -1;
+
+ /*
+ if (timeout_ms == 0) {
+ // set non-blocking mode
+ uint8_t arg = SOCK_IO_NONBLOCK;
+ WIZCHIP_EXPORT(ctlsocket)(socket->u_param.fileno, CS_SET_IOMODE, &arg);
+ }
+ */
+}
+
+STATIC int wiznet5k_socket_ioctl(mod_network_socket_obj_t *socket, mp_uint_t request, mp_uint_t arg, int *_errno) {
+ // TODO
+ *_errno = EINVAL;
+ return -1;
+}
+
+#if 0
+STATIC void wiznet5k_socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+ wiznet5k_socket_obj_t *self = self_in;
+ print(env, "<WIZNET5K.socket sn=%u MR=0x%02x>", self->sn, getSn_MR(self->sn));
+}
+
+STATIC mp_obj_t wiznet5k_socket_disconnect(mp_obj_t self_in) {
+ mp_int_t ret = WIZCHIP_EXPORT(disconnect)(self->sn);
+ return 0;
+}
+#endif
+
+/******************************************************************************/
+// Micro Python bindings
+
/// \classmethod \constructor(spi, pin_cs, pin_rst)
-/// Create and return a WIZnet5k object.
+/// 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, 3, 3, false);
@@ -222,7 +374,7 @@ STATIC mp_obj_t wiznet5k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
uint8_t sn_size[16] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; // 2k buffer for each socket
ctlwizchip(CW_INIT_WIZCHIP, sn_size);
- // TODO make this configurable!
+ // set some sensible default values; they are configurable using ifconfig method
wiz_NetInfo netinfo = {
.mac = {0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef},
.ip = {192, 168, 0, 18},
@@ -233,6 +385,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);
+ // seems we need a small delay after init
+ HAL_Delay(250);
+
// register with network module
mod_network_register_nic(&wiznet5k_obj);
@@ -241,7 +396,7 @@ STATIC mp_obj_t wiznet5k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t
}
/// \method regs()
-/// Dump WIZnet5k registers.
+/// Dump WIZNET5K registers.
STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
//wiznet5k_obj_t *self = self_in;
printf("Wiz CREG:");
@@ -265,9 +420,9 @@ STATIC mp_obj_t wiznet5k_regs(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_regs_obj, wiznet5k_regs);
-/// \method ipaddr([(ip, subnet, gateway, dns)])
+/// \method ifconfig([(ip, subnet, gateway, dns)])
/// Get/set IP address, subnet mask, gateway and DNS.
-STATIC mp_obj_t wiznet5k_ipaddr(mp_uint_t n_args, const mp_obj_t *args) {
+STATIC mp_obj_t wiznet5k_ifconfig(mp_uint_t n_args, const mp_obj_t *args) {
wiz_NetInfo netinfo;
ctlnetwork(CN_GET_NETINFO, &netinfo);
if (n_args == 1) {
@@ -291,11 +446,11 @@ STATIC mp_obj_t wiznet5k_ipaddr(mp_uint_t n_args, const mp_obj_t *args) {
return mp_const_none;
}
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ipaddr_obj, 1, 2, wiznet5k_ipaddr);
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(wiznet5k_ifconfig_obj, 1, 2, wiznet5k_ifconfig);
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_ifconfig), (mp_obj_t)&wiznet5k_ifconfig_obj },
};
STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
@@ -303,172 +458,22 @@ STATIC MP_DEFINE_CONST_DICT(wiznet5k_locals_dict, wiznet5k_locals_dict_table);
const mod_network_nic_type_t mod_network_nic_type_wiznet5k = {
.base = {
{ &mp_type_type },
- .name = MP_QSTR_WIZnet5k,
- .print = wiznet5k_print,
+ .name = MP_QSTR_WIZNET5K,
.make_new = wiznet5k_make_new,
.locals_dict = (mp_obj_t)&wiznet5k_locals_dict,
},
- .socket = wiznet5k_socket,
.gethostbyname = wiznet5k_gethostbyname,
-};
-
-/******************************************************************************/
-// Micro Python bindings; WIZnet5x00 socket class
-
-typedef struct _wiznet5k_socket_obj_t {
- mp_obj_base_t base;
- uint8_t sn;
- 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;
- s->sn = sn;
- s->type = type;
- return s;
-}
-
-STATIC void wiznet5k_socket_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
- wiznet5k_socket_obj_t *self = self_in;
- print(env, "<WIZnet5k.socket sn=%u MR=0x%02x>", self->sn, getSn_MR(self->sn));
-}
-
-STATIC mp_obj_t wiznet5k_socket_close(mp_obj_t self_in) {
- wiznet5k_socket_obj_t *self = self_in;
- wiznet5k_obj.socket_used &= ~(1 << self->sn);
- mp_int_t ret = WIZCHIP_EXPORT(close)(self->sn);
- check_sock_return_value(ret);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_socket_close_obj, wiznet5k_socket_close);
-
-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 = mod_network_parse_inet_addr(addr_in, ip);
-
- // open the socket in server mode
- mp_int_t ret = WIZCHIP_EXPORT(socket)(self->sn, self->type, port, 0);
- check_sock_return_value(ret);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_bind_obj, wiznet5k_socket_bind);
-
-STATIC mp_obj_t wiznet5k_socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
- wiznet5k_socket_obj_t *self = self_in;
- mp_int_t ret = WIZCHIP_EXPORT(listen)(self->sn);
- check_sock_return_value(ret);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_listen_obj, wiznet5k_socket_listen);
-
-STATIC mp_obj_t wiznet5k_socket_accept(mp_obj_t self_in) {
- //wiznet5k_socket_obj_t *self = self_in;
-
- // TODO what to do here exactly?
-
- mp_obj_t tuple[2] = {self_in, mp_const_none};
- return mp_obj_new_tuple(2, tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_socket_accept_obj, wiznet5k_socket_accept);
-
-STATIC mp_obj_t wiznet5k_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
- wiznet5k_socket_obj_t *self = self_in;
-
- // first open the socket in client mode
- mp_int_t ret = WIZCHIP_EXPORT(socket)(self->sn, self->type, 0, 0);
- check_sock_return_value(ret);
-
- // now connect
- uint8_t ip[IPADDR_BUF_SIZE];
- mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip);
- ret = WIZCHIP_EXPORT(connect)(self->sn, ip, port);
- check_sock_return_value(ret);
-
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_connect_obj, wiznet5k_socket_connect);
-
-STATIC mp_obj_t wiznet5k_socket_disconnect(mp_obj_t self_in) {
- wiznet5k_socket_obj_t *self = self_in;
- mp_int_t ret = WIZCHIP_EXPORT(disconnect)(self->sn);
- check_sock_return_value(ret);
- return mp_const_none;
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(wiznet5k_socket_disconnect_obj, wiznet5k_socket_disconnect);
-
-STATIC mp_obj_t wiznet5k_socket_send(mp_obj_t self_in, mp_obj_t data_in) {
- wiznet5k_socket_obj_t *self = self_in;
- mp_buffer_info_t bufinfo;
- mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
- mp_int_t ret = WIZCHIP_EXPORT(send)(self->sn, bufinfo.buf, bufinfo.len);
- check_sock_return_value(ret);
- return mp_obj_new_int(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_send_obj, wiznet5k_socket_send);
-
-STATIC mp_obj_t wiznet5k_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
- wiznet5k_socket_obj_t *self = self_in;
- mp_int_t len = mp_obj_get_int(len_in);
- byte *buf;
- mp_obj_t ret_obj = mp_obj_str_builder_start(&mp_type_bytes, len, &buf);
- mp_int_t ret = WIZCHIP_EXPORT(recv)(self->sn, buf, len);
- check_sock_return_value(ret);
- return mp_obj_str_builder_end_with_len(ret_obj, len);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_recv_obj, wiznet5k_socket_recv);
-
-STATIC mp_obj_t wiznet5k_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
- wiznet5k_socket_obj_t *self = self_in;
- 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 = mod_network_parse_inet_addr(addr_in, ip);
- mp_int_t ret = WIZCHIP_EXPORT(sendto)(self->sn, bufinfo.buf, bufinfo.len, ip, port);
- check_sock_return_value(ret);
- return mp_obj_new_int(ret);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_3(wiznet5k_socket_sendto_obj, wiznet5k_socket_sendto);
-
-STATIC mp_obj_t wiznet5k_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
- wiznet5k_socket_obj_t *self = self_in;
- mp_int_t len = mp_obj_get_int(len_in);
- uint8_t *buf = m_new(uint8_t, len);
- uint8_t ip[4];
- uint16_t port;
- mp_int_t ret = WIZCHIP_EXPORT(recvfrom)(self->sn, buf, len, ip, &port);
- check_sock_return_value(ret);
- mp_obj_t tuple[2] = {
- mp_obj_new_bytes(buf, ret),
- mod_network_format_inet_addr(ip, port),
- };
- return mp_obj_new_tuple(2, tuple);
-}
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(wiznet5k_socket_recvfrom_obj, wiznet5k_socket_recvfrom);
-
-STATIC const mp_map_elem_t wiznet5k_socket_locals_dict_table[] = {
- { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&wiznet5k_socket_close_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&wiznet5k_socket_bind_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&wiznet5k_socket_listen_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&wiznet5k_socket_accept_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&wiznet5k_socket_connect_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&wiznet5k_socket_disconnect_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&wiznet5k_socket_send_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&wiznet5k_socket_recv_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&wiznet5k_socket_sendto_obj },
- { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&wiznet5k_socket_recvfrom_obj },
-};
-
-STATIC MP_DEFINE_CONST_DICT(wiznet5k_socket_locals_dict, wiznet5k_socket_locals_dict_table);
-
-STATIC const mp_obj_type_t wiznet5k_socket_type = {
- { &mp_type_type },
- .name = MP_QSTR_socket,
- .print = wiznet5k_socket_print,
- .locals_dict = (mp_obj_t)&wiznet5k_socket_locals_dict,
+ .socket = wiznet5k_socket_socket,
+ .close = wiznet5k_socket_close,
+ .bind = wiznet5k_socket_bind,
+ .listen = wiznet5k_socket_listen,
+ .accept = wiznet5k_socket_accept,
+ .connect = wiznet5k_socket_connect,
+ .send = wiznet5k_socket_send,
+ .recv = wiznet5k_socket_recv,
+ .sendto = wiznet5k_socket_sendto,
+ .recvfrom = wiznet5k_socket_recvfrom,
+ .setsockopt = wiznet5k_socket_setsockopt,
+ .settimeout = wiznet5k_socket_settimeout,
+ .ioctl = wiznet5k_socket_ioctl,
};
diff --git a/stmhal/modusocket.c b/stmhal/modusocket.c
index 048f052982..1c0b036d34 100644
--- a/stmhal/modusocket.c
+++ b/stmhal/modusocket.c
@@ -41,43 +41,346 @@
#include "runtime.h"
#include "modnetwork.h"
-/// \module usocket - socket module
-///
-/// Socket functionality.
-
-/// \function 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} },
- };
+/******************************************************************************/
+// socket class
- // 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);
+STATIC const mp_obj_type_t socket_type;
- // 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;
+// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
+STATIC mp_obj_t 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);
+
+ // create socket object (not bound to any NIC yet)
+ mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ s->base.type = (mp_obj_t)&socket_type;
+ s->nic = MP_OBJ_NULL;
+ s->nic_type = NULL;
+ s->u_param.domain = MOD_NETWORK_AF_INET;
+ s->u_param.type = MOD_NETWORK_SOCK_STREAM;
+ s->u_param.fileno = -1;
+ if (n_args >= 1) {
+ s->u_param.domain = mp_obj_get_int(args[0]);
+ if (n_args >= 2) {
+ s->u_param.type = mp_obj_get_int(args[1]);
+ if (n_args >= 4) {
+ s->u_param.fileno = mp_obj_get_int(args[3]);
}
}
}
- nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available NIC"));
+ return s;
+}
+
+STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) {
+ if (self->nic == MP_OBJ_NULL) {
+ // select NIC based on IP
+ self->nic = mod_network_find_nic(ip);
+ self->nic_type = (mod_network_nic_type_t*)mp_obj_get_type(self->nic);
+
+ // call the NIC to open the socket
+ int _errno;
+ if (self->nic_type->socket(self, &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+ }
+}
+// method socket.close()
+STATIC mp_obj_t socket_close(mp_obj_t self_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic != MP_OBJ_NULL) {
+ self->nic_type->close(self);
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close);
+
+// method socket.bind(address)
+STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to bind the socket
+ int _errno;
+ if (self->nic_type->bind(self, ip, port, &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
+
+// method socket.listen(backlog)
+STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) {
+ mod_network_socket_obj_t *self = self_in;
+
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ // TODO I think we can listen even if not bound...
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+ }
+
+ int _errno;
+ if (self->nic_type->listen(self, mp_obj_get_int(backlog), &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
+
+// method socket.accept()
+STATIC mp_obj_t socket_accept(mp_obj_t self_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // create new socket object
+ mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t);
+ socket2->base.type = (mp_obj_t)&socket_type;
+ socket2->nic = self->nic;
+ socket2->nic_type = self->nic_type;
+
+ // accept incoming connection
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port;
+ int _errno;
+ if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+
+ // make the return value
+ mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
+ client->items[0] = socket2;
+ client->items[1] = mod_network_format_inet_addr(ip, port);
+
+ return client;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
+
+// method socket.connect(address)
+STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to connect the socket
+ int _errno;
+ if (self->nic_type->connect(self, ip, port, &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
+
+// method socket.send(bytes)
+STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EPIPE)));
+ }
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ);
+ int _errno;
+ mp_uint_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno);
+ if (ret == -1) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+ return mp_obj_new_int_from_uint(ret);
}
-STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_usocket_socket_obj, 0, mod_usocket_socket);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
+
+// method socket.recv(bufsize)
+STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+ }
+ mp_int_t len = mp_obj_get_int(len_in);
+ byte *buf;
+ mp_obj_t ret_obj = mp_obj_str_builder_start(&mp_type_bytes, len, &buf);
+ int _errno;
+ mp_uint_t ret = self->nic_type->recv(self, buf, len, &_errno);
+ if (ret == -1) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+ if (ret == 0) {
+ return mp_const_empty_bytes;
+ }
+ return mp_obj_str_builder_end_with_len(ret_obj, ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
+
+// method socket.sendto(bytes, address)
+STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
+ mod_network_socket_obj_t *self = self_in;
+
+ // get the data
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
+
+ // get address
+ uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE];
+ mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip);
+
+ // check if we need to select a NIC
+ socket_select_nic(self, ip);
+
+ // call the NIC to sendto
+ int _errno;
+ mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno);
+ if (ret == -1) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+
+ return mp_obj_new_int(ret);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
+
+// method socket.recvfrom(bufsize)
+STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+ }
+ mp_int_t len = mp_obj_get_int(len_in);
+ byte *buf;
+ mp_obj_t ret_obj = mp_obj_str_builder_start(&mp_type_bytes, len, &buf);
+ byte ip[4];
+ mp_uint_t port;
+ int _errno;
+ mp_int_t ret = self->nic_type->recvfrom(self, buf, len, ip, &port, &_errno);
+ if (ret == -1) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+ if (ret == 0) {
+ ret_obj = mp_const_empty_bytes;
+ } else {
+ ret_obj = mp_obj_str_builder_end_with_len(ret_obj, ret);
+ }
+ mp_obj_t tuple[2] = {
+ ret_obj,
+ mod_network_format_inet_addr(ip, port),
+ };
+ return mp_obj_new_tuple(2, tuple);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
+
+// method socket.setsockopt(level, optname, value)
+STATIC mp_obj_t socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
+ mod_network_socket_obj_t *self = args[0];
+
+ mp_int_t level = mp_obj_get_int(args[1]);
+ mp_int_t opt = mp_obj_get_int(args[2]);
+
+ const void *optval;
+ mp_uint_t optlen;
+ if (mp_obj_is_integer(args[3])) {
+ int val = mp_obj_int_get(args[3]);
+ optval = &val;
+ optlen = sizeof(val);
+ } else {
+ mp_buffer_info_t bufinfo;
+ mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
+ optval = bufinfo.buf;
+ optlen = bufinfo.len;
+ }
+
+ int _errno;
+ if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
+
+// method socket.settimeout(value)
+// timeout=0 means non-blocking
+// timeout=None means blocking
+// otherwise, timeout is in seconds
+STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
+ mod_network_socket_obj_t *self = self_in;
+ if (self->nic == MP_OBJ_NULL) {
+ // not connected
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN)));
+ }
+ mp_uint_t timeout;
+ if (timeout_in == mp_const_none) {
+ timeout = -1;
+ } else {
+ timeout = 1000 * mp_obj_get_float(timeout_in);
+ }
+ int _errno;
+ if (self->nic_type->settimeout(self, timeout, &_errno) != 0) {
+ nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno)));
+ }
+ return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
+
+// method socket.setblocking(flag)
+STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) {
+ if (mp_obj_is_true(blocking)) {
+ return socket_settimeout(self_in, mp_const_none);
+ } else {
+ return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0));
+ }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
+
+STATIC const mp_map_elem_t socket_locals_dict_table[] = {
+ { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj },
+ { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj },
+};
+
+STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
+
+mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) {
+ mod_network_socket_obj_t *self = self_in;
+ return self->nic_type->ioctl(self, request, arg, errcode);
+}
+
+STATIC const mp_stream_p_t socket_stream_p = {
+ .ioctl = socket_ioctl,
+ .is_text = false,
+};
+
+STATIC const mp_obj_type_t socket_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_socket,
+ .make_new = socket_make_new,
+ .stream_p = &socket_stream_p,
+ .locals_dict = (mp_obj_t)&socket_locals_dict,
+};
+
+/******************************************************************************/
+// usocket module
-/// \function getaddrinfo(host, port)
+// function usocket.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);
@@ -111,7 +414,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getadd
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_socket), (mp_obj_t)&socket_type },
{ MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_usocket_getaddrinfo_obj },
// class constants
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index 3b89dc9f1a..e274c4f178 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -378,6 +378,18 @@ Q(show)
Q(usocket)
Q(socket)
Q(getaddrinfo)
+Q(bind)
+Q(listen)
+Q(accept)
+Q(connect)
+Q(send)
+Q(recv)
+Q(sendto)
+Q(recvfrom)
+Q(setblocking)
+Q(setsockopt)
+Q(settimeout)
+Q(close)
Q(AF_INET)
Q(AF_INET6)
Q(SOCK_STREAM)
@@ -388,39 +400,19 @@ Q(SOCK_RAW)
Q(network)
Q(route)
-// for WIZnet5k class
+// for WIZNET5K class
#if MICROPY_PY_WIZNET5K
-Q(wiznet5k)
-Q(WIZnet5k)
+Q(WIZNET5K)
Q(regs)
Q(ipaddr)
-Q(socket)
-Q(family)
-Q(type)
-Q(fileno)
-Q(close)
-Q(bind)
-Q(listen)
-Q(accept)
-Q(connect)
-Q(disconnect)
-Q(send)
-Q(recv)
-Q(sendto)
-Q(recvfrom)
-Q(gethostbyname)
-Q(AF_INET)
-Q(SOCK_STREAM)
-Q(SOCK_DGRAM)
#endif
-// for CC3k class
+// for CC3K class
#if MICROPY_PY_CC3K
-Q(cc3k)
-Q(CC3k)
+Q(CC3K)
Q(connect)
Q(disconnect)
-Q(is_connected)
+Q(isconnected)
Q(ifconfig)
Q(patch_version)
Q(patch_program)
@@ -431,16 +423,6 @@ Q(ssid)
Q(key)
Q(security)
Q(bssid)
-Q(send)
-Q(recv)
-Q(bind)
-Q(listen)
-Q(accept)
-Q(connect)
-Q(settimeout)
-Q(setblocking)
-Q(close)
-Q(__del__)
#endif
// for stm module