diff options
Diffstat (limited to 'stmhal')
-rw-r--r-- | stmhal/Makefile | 40 | ||||
-rw-r--r-- | stmhal/boards/HYDRABUS/mpconfigboard.h | 1 | ||||
-rw-r--r-- | stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h | 1 | ||||
-rw-r--r-- | stmhal/boards/PYBV10/mpconfigboard.h | 1 | ||||
-rw-r--r-- | stmhal/boards/PYBV3/mpconfigboard.h | 1 | ||||
-rw-r--r-- | stmhal/boards/PYBV4/mpconfigboard.h | 1 | ||||
-rw-r--r-- | stmhal/boards/STM32F4DISC/mpconfigboard.h | 1 | ||||
-rw-r--r-- | stmhal/modcc3k.c | 736 | ||||
-rw-r--r-- | stmhal/mpconfigport.h | 8 | ||||
-rw-r--r-- | stmhal/mpconfigport.mk | 3 | ||||
-rw-r--r-- | stmhal/qstrdefsport.h | 43 | ||||
-rw-r--r-- | stmhal/spi.c | 8 | ||||
-rw-r--r-- | stmhal/spi.h | 1 |
13 files changed, 822 insertions, 23 deletions
diff --git a/stmhal/Makefile b/stmhal/Makefile index 4978185602..f14a881c5b 100644 --- a/stmhal/Makefile +++ b/stmhal/Makefile @@ -22,7 +22,6 @@ HAL_DIR=hal USBDEV_DIR=usbdev #USBHOST_DIR=usbhost FATFS_DIR=fatfs -CC3K_DIR=cc3k DFU=../tools/dfu.py # may need to prefix dfu-util with sudo DFU_UTIL ?= dfu-util @@ -39,7 +38,6 @@ INC += -I$(HAL_DIR)/inc INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc_msc_hid/inc #INC += -I$(USBHOST_DIR) INC += -I$(FATFS_DIR)/src -INC += -I$(CC3K_DIR) CFLAGS_CORTEX_M4 = -mthumb -mtune=cortex-m4 -mabi=aapcs-linux -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -fsingle-precision-constant -Wdouble-promotion CFLAGS = $(INC) -Wall -Werror -ansi -std=gnu99 -nostdlib $(CFLAGS_MOD) $(CFLAGS_CORTEX_M4) $(COPT) @@ -187,19 +185,6 @@ SRC_FATFS = $(addprefix $(FATFS_DIR)/src/,\ option/ccsbcs.c \ ) -SRC_CC3K = $(addprefix $(CC3K_DIR)/,\ - cc3000_common.c \ - evnt_handler.c \ - hci.c \ - netapp.c \ - nvmem.c \ - security.c \ - socket.c \ - wlan.c \ - ccspi.c \ - pybcc3k.c \ - ) - ifeq ($(MICROPY_PY_WIZNET5K),1) WIZNET5K_DIR=drivers/wiznet5k INC += -I$(TOP)/$(WIZNET5K_DIR) @@ -213,6 +198,30 @@ SRC_MOD += $(addprefix $(WIZNET5K_DIR)/,\ ) endif +# for CC3000 module +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 += $(addprefix $(CC3000_DIR)/src/,\ + cc3000_common.c \ + evnt_handler.c \ + hci.c \ + netapp.c \ + nvmem.c \ + security.c \ + socket.c \ + wlan.c \ + ccspi.c \ + inet_ntop.c \ + inet_pton.c \ + ) +# patch.c \ +# patch_prog.c \ + ) +endif + OBJ = OBJ += $(PY_O) OBJ += $(addprefix $(BUILD)/, $(SRC_LIB:.c=.o)) @@ -221,7 +230,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_USBDEV:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_CC3K:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(BUILD)/pins_$(BOARD).o diff --git a/stmhal/boards/HYDRABUS/mpconfigboard.h b/stmhal/boards/HYDRABUS/mpconfigboard.h index db49434b5b..18d1df19db 100644 --- a/stmhal/boards/HYDRABUS/mpconfigboard.h +++ b/stmhal/boards/HYDRABUS/mpconfigboard.h @@ -16,7 +16,6 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (1) -#define MICROPY_HW_ENABLE_CC3K (0) // USRSW/UBTN (Needs Jumper UBTN) is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) diff --git a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h index 2679aee576..c32e0d29e5 100644 --- a/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h +++ b/stmhal/boards/NETDUINO_PLUS_2/mpconfigboard.h @@ -20,7 +20,6 @@ #define MICROPY_HW_ENABLE_I2C1 (0) #define MICROPY_HW_ENABLE_SPI1 (0) #define MICROPY_HW_ENABLE_SPI3 (0) -#define MICROPY_HW_ENABLE_CC3K (0) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_B11) diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index c52d61b667..977fabe402 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -17,7 +17,6 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) -#define MICROPY_HW_ENABLE_CC3K (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) diff --git a/stmhal/boards/PYBV3/mpconfigboard.h b/stmhal/boards/PYBV3/mpconfigboard.h index 43d860a0cc..048812748d 100644 --- a/stmhal/boards/PYBV3/mpconfigboard.h +++ b/stmhal/boards/PYBV3/mpconfigboard.h @@ -16,7 +16,6 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) -#define MICROPY_HW_ENABLE_CC3K (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_A13) diff --git a/stmhal/boards/PYBV4/mpconfigboard.h b/stmhal/boards/PYBV4/mpconfigboard.h index a278dea9fb..5bb7f03b2f 100644 --- a/stmhal/boards/PYBV4/mpconfigboard.h +++ b/stmhal/boards/PYBV4/mpconfigboard.h @@ -16,7 +16,6 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) -#define MICROPY_HW_ENABLE_CC3K (0) // USRSW has no pullup or pulldown, and pressing the switch makes the input go low #define MICROPY_HW_USRSW_PIN (pin_B3) diff --git a/stmhal/boards/STM32F4DISC/mpconfigboard.h b/stmhal/boards/STM32F4DISC/mpconfigboard.h index 10bbe45188..2e27694775 100644 --- a/stmhal/boards/STM32F4DISC/mpconfigboard.h +++ b/stmhal/boards/STM32F4DISC/mpconfigboard.h @@ -16,7 +16,6 @@ #define MICROPY_HW_ENABLE_I2C1 (1) #define MICROPY_HW_ENABLE_SPI1 (1) #define MICROPY_HW_ENABLE_SPI3 (0) -#define MICROPY_HW_ENABLE_CC3K (0) // USRSW is pulled low. Pressing the button makes the input go high. #define MICROPY_HW_USRSW_PIN (pin_A0) diff --git a/stmhal/modcc3k.c b/stmhal/modcc3k.c new file mode 100644 index 0000000000..4e21033bb3 --- /dev/null +++ b/stmhal/modcc3k.c @@ -0,0 +1,736 @@ +/* + * 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. + +// We can't include errno.h because CC3000 defines its own errnos. +// (And they are different to the standard ones!) + +#include <std.h> +#include <string.h> + +#include "stm32f4xx_hal.h" +#include "mpconfig.h" +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "objtuple.h" +#include "stream.h" +#include "runtime.h" +#include "pin.h" +#include "genhdr/pins.h" +#include "spi.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" + +STATIC const mp_obj_type_t cc3k_type; +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); + +STATIC volatile uint32_t fd_state = 0; +STATIC volatile bool wlan_connected = false; +STATIC volatile bool ip_obtained = false; + +STATIC int cc3k_get_fd_state(int fd) { + return (fd_state & (1<<fd)); +} + +STATIC void cc3k_clear_fd_state(int fd) { + // reset socket state + fd_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 + fd_state |= (1<<((uint8_t)data[0])); + break; + } +} + +/******************************************************************************/ +// 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 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 = &cc3k_type; + + return cc3k; +} + +STATIC mp_obj_t cc3k_connect(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + int ssid_len =0; + const char *ssid = NULL; + const char *bssid = NULL; + + int key_len =0; + int sec = WLAN_SEC_UNSEC; + const char *key = NULL; + + mp_map_elem_t *kw_key, *kw_sec, *kw_bssid; + + ssid = mp_obj_str_get_str(args[1]); + ssid_len = strlen(ssid); + + // get KW args + kw_key = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("key")), MP_MAP_LOOKUP); + kw_sec = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("sec")), MP_MAP_LOOKUP); + kw_bssid = mp_map_lookup(kw_args, MP_OBJ_NEW_QSTR(qstr_from_str("bssid")), MP_MAP_LOOKUP); + + // get key and sec + if (kw_key && kw_sec) { + key = mp_obj_str_get_str(kw_key->value); + key_len = strlen(key); + + sec = mp_obj_get_int(kw_sec->value); + if (!(WLAN_SEC_UNSEC < sec && sec <= WLAN_SEC_WPA2)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid security mode")); + } + } + + // get bssid + if (kw_bssid != NULL) { + bssid = mp_obj_str_get_str(kw_bssid->value); + } + + // 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, 2, 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) { + //patch_prog_start(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(cc3k_patch_program_obj, cc3k_patch_program); + +/// \method socket(family=AF_INET, type=SOCK_STREAM, fileno=-1) +/// Create a socket. +STATIC const mp_arg_t cc3k_socket_args[] = { + { MP_QSTR_family, MP_ARG_INT, {.u_int = AF_INET} }, + { MP_QSTR_type, MP_ARG_INT, {.u_int = SOCK_STREAM} }, +}; +#define PYB_CC3K_SOCKET_NUM_ARGS MP_ARRAY_SIZE(cc3k_socket_args) +STATIC mp_obj_t cc3k_socket(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + // parse args + mp_arg_val_t vals[PYB_CC3K_SOCKET_NUM_ARGS]; + mp_arg_parse_all(n_args - 1, args + 1, kw_args, PYB_CC3K_SOCKET_NUM_ARGS, cc3k_socket_args, vals); + + return cc3k_socket_new(vals[0].u_int, vals[1].u_int, 0); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(cc3k_socket_obj, 1, cc3k_socket); + +STATIC mp_obj_t cc3k_gethostbyname(mp_obj_t self_in, mp_obj_t hostname) { + mp_uint_t len; + const char *host = mp_obj_str_get_data(hostname, &len); + uint32_t ip; + + if (gethostbyname((char*)host, len, &ip) < 0) { + // TODO raise appropriate exception + printf("gethostbyname failed\n"); + return mp_const_none; + } + + if (ip == 0) { + // unknown host + // TODO CPython raises: socket.gaierror: [Errno -2] Name or service not known + printf("Name or service not known\n"); + return mp_const_none; + } + + // turn the ip address into a string (could use inet_ntop, but this here is much more efficient) + VSTR_FIXED(ip_str, 16); + vstr_printf(&ip_str, "%u.%u.%u.%u", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); + mp_obj_t ret = mp_obj_new_str(ip_str.buf, ip_str.len, false); + + return ret; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(cc3k_gethostbyname_obj, cc3k_gethostbyname); + +STATIC const mp_map_elem_t cc3k_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&cc3k_connect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_disconnect), (mp_obj_t)&cc3k_disconnect_obj }, + { 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 }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&cc3k_socket_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_gethostbyname), (mp_obj_t)&cc3k_gethostbyname_obj }, + + // class constants + + { MP_OBJ_NEW_QSTR(MP_QSTR_WEP), MP_OBJ_NEW_SMALL_INT(WLAN_SEC_WEP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WPA), MP_OBJ_NEW_SMALL_INT(WLAN_SEC_WPA) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_WPA2), MP_OBJ_NEW_SMALL_INT(WLAN_SEC_WPA2) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IP), MP_OBJ_NEW_SMALL_INT(IPPROTO_IP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_ICMP), MP_OBJ_NEW_SMALL_INT(IPPROTO_ICMP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IPV4), MP_OBJ_NEW_SMALL_INT(IPPROTO_IPV4) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_IPV6), MP_OBJ_NEW_SMALL_INT(IPPROTO_IPV6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(IPPROTO_RAW) }, +}; + +STATIC MP_DEFINE_CONST_DICT(cc3k_locals_dict, cc3k_locals_dict_table); + +STATIC const mp_obj_type_t cc3k_type = { + { &mp_type_type }, + .name = MP_QSTR_CC3k, + //.print = cc3k_print, + .make_new = cc3k_make_new, + .locals_dict = (mp_obj_t)&cc3k_locals_dict, +}; + +/******************************************************************************/ +// Micro Python bindings; CC3k socket class + +#define EPIPE (32) +//#define MAX_FD (8) +#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 mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol) { + // 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 = socket(family, type, protocol); + if (s->fd < 0) { + m_del_obj(cc3k_socket_obj_t, s); + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "socket failed")); + } + + // clear socket state + cc3k_clear_fd_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_uint_t cc3k_socket_send(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) { + cc3k_socket_obj_t *self = self_in; + + if (cc3k_get_fd_state(self->fd)) { + closesocket(self->fd); + *errcode = EPIPE; + return 0; + } + + // CC3K does not handle fragmentation, and will overflow, + // split the packet into smaller ones and send them out. + int bytes = 0; + while (bytes < size) { + int n = MIN((size-bytes), MAX_TX_PACKET); + n = send(self->fd, buf+bytes, n, 0); + if (n <= 0) { + bytes = n; + *errcode = errno; + break; + } + bytes += n; + } + + return bytes; +} + +STATIC mp_uint_t cc3k_socket_recv(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { + cc3k_socket_obj_t *self = self_in; + + if (cc3k_get_fd_state(self->fd)) { + closesocket(self->fd); + return 0; + } + + // recv MAX_RX_PACKET + int bytes = 0; + while (bytes < size) { + int n = MIN((size-bytes), MAX_RX_PACKET); + n = recv(self->fd, buf+bytes, n, 0); + if (n == 0) { + break; + } else if (n < 0) { + bytes = n; + *errcode = errno; + break; + } + bytes += n; + } + + return bytes; +} + +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 (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 (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 = accept(self->fd, &addr, &addr_len)) < 0) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "accept failed")); + } + + // clear socket state + cc3k_clear_fd_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 = 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 (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 (setsockopt(self->fd, SOL_SOCKET, SOCKOPT_RECV_NONBLOCK, &optval, optlen) != 0 || + 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; + 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[] = { + // TODO read/write/send/recv distinctions + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&mp_stream_write_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&mp_stream_read_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); + +STATIC const mp_stream_p_t cc3k_socket_stream_p = { + .read = cc3k_socket_recv, + .write = cc3k_socket_send, +}; + +STATIC const mp_obj_type_t cc3k_socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .print = cc3k_socket_print, + .getiter = NULL, + .iternext = NULL, + .stream_p = &cc3k_socket_stream_p, + .locals_dict = (mp_obj_t)&cc3k_socket_locals_dict, +}; + +// the following code is for select, which is yet to be implemented +#if 0 +#define MP_ASSERT_TYPE(obj, type) \ + do { \ + __typeof__ (obj) _a = (obj); \ + __typeof__ (type) _b = (type); \ + if (!MP_OBJ_IS_TYPE(_a, _b)) { \ + nlr_jump(mp_obj_new_exception_msg_varg( \ + &mp_type_TypeError, \ + "can't convert %s to %s", \ + mp_obj_get_type_str(_a), \ + _b->name)); \ + } \ + } while(0) + +// select helper functions +STATIC void set_fds(int *nfds, mp_obj_t *fdlist, mp_uint_t fdlist_len, fd_set *fdset) { + + // clear fd set + FD_ZERO(fdset); + + // add sockets to fd set + for (int i=0; i<fdlist_len; i++) { + socket_t *s = fdlist[i]; + + // check arg type + MP_ASSERT_TYPE(s, &cc3k_socket_type); + + // add to fd set + FD_SET(s->fd, fdset); + + if (s->fd > (*nfds)) { + *nfds = s->fd; + } + } +} + +STATIC void get_fds(mp_obj_t *fdlist, mp_uint_t fdlist_len, mp_obj_t *fdlist_out, fd_set *fdset) { + for (int i=0; i<fdlist_len; i++) { + socket_t *s = fdlist[i]; + if (FD_ISSET(s->fd, fdset)) { + socket_t *socket_obj = m_new_obj_with_finaliser(socket_t); + socket_obj->base.type = (mp_obj_t)&socket_type; + socket_obj->fd = s->fd; + mp_obj_list_append(fdlist_out, socket_obj); + } + } +} + +STATIC mp_obj_t cc3k_select(mp_uint_t n_args, const mp_obj_t *args) { + int nfds=0; //highest-numbered fd plus 1 + timeval tv={0}; + fd_set rfds, wfds, xfds; + + mp_obj_t *rlist, *wlist, *xlist; + mp_uint_t rlist_len, wlist_len, xlist_len; + + // read args + mp_obj_get_array(args[0], &rlist_len, &rlist); + mp_obj_get_array(args[1], &wlist_len, &wlist); + mp_obj_get_array(args[2], &xlist_len, &xlist); + + if (n_args == 4) { + float timeout = mp_obj_get_float(args[3]); + tv.tv_sec = (int)timeout; + tv.tv_usec = (timeout-(int)timeout)*1000*1000; + } + + // add fds to their respective sets + set_fds(&nfds, rlist, rlist_len, &rfds); + set_fds(&nfds, wlist, wlist_len, &wfds); + set_fds(&nfds, xlist, xlist_len, &xfds); + + // call select + nfds = select(nfds+1, &rfds, &wfds, &xfds, &tv); + + // if any of the read sockets is closed, we add it to the read fd set, + // a subsequent call to recv() returns 0. This behavior is consistent with BSD. + for (int i=0; i<rlist_len; i++) { + socket_t *s = rlist[i]; + if (cc3k_get_fd_state(s->fd)) { + FD_SET(s->fd, &rfds); + nfds = (nfds > s->fd)? nfds:s->fd; + } + } + + // return value; a tuple of 3 lists + mp_obj_t fds[3] = { + mp_obj_new_list(0, NULL), + mp_obj_new_list(0, NULL), + mp_obj_new_list(0, NULL) + }; + + // On success, select() returns the number of file descriptors contained + // in the three returned descriptor sets which may be zero if the timeout + // expires before anything interesting happens, -1 is returned on error. + if (nfds == -1) { // select failed + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "select failed")); + } else if (nfds) { // an fd is ready + get_fds(rlist, rlist_len, fds[0], &rfds); + get_fds(wlist, wlist_len, fds[1], &wfds); + get_fds(xlist, xlist_len, fds[2], &xfds); + } // select timedout + + return mp_obj_new_tuple(3, fds); +} +#endif + +/******************************************************************************/ +// Micro Python bindings; CC3k module + +STATIC const mp_map_elem_t mp_module_cc3k_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_cc3k) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CC3k), (mp_obj_t)&cc3k_type }, +}; + +STATIC const mp_obj_dict_t mp_module_cc3k_globals = { + .base = {&mp_type_dict}, + .map = { + .all_keys_are_qstrs = 1, + .table_is_fixed_array = 1, + .used = MP_ARRAY_SIZE(mp_module_cc3k_globals_table), + .alloc = MP_ARRAY_SIZE(mp_module_cc3k_globals_table), + .table = (mp_map_elem_t*)mp_module_cc3k_globals_table, + }, +}; + +const mp_obj_module_t mp_module_cc3k = { + .base = { &mp_type_module }, + .name = MP_QSTR_cc3k, + .globals = (mp_obj_dict_t*)&mp_module_cc3k_globals, +}; diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h index 5e6faa4df2..8fe2f21027 100644 --- a/stmhal/mpconfigport.h +++ b/stmhal/mpconfigport.h @@ -85,6 +85,13 @@ extern const struct _mp_obj_module_t mp_module_wiznet5k; #define MICROPY_PY_WIZNET5K_DEF #endif +#if MICROPY_PY_CC3K +extern const struct _mp_obj_module_t mp_module_cc3k; +#define MICROPY_PY_CC3K_DEF { MP_OBJ_NEW_QSTR(MP_QSTR_cc3k), (mp_obj_t)&mp_module_cc3k }, +#else +#define MICROPY_PY_CC3K_DEF +#endif + #define MICROPY_PORT_BUILTIN_MODULES \ { MP_OBJ_NEW_QSTR(MP_QSTR_os), (mp_obj_t)&os_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \ @@ -92,6 +99,7 @@ extern const struct _mp_obj_module_t mp_module_wiznet5k; { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_select), (mp_obj_t)&mp_module_select }, \ MICROPY_PY_WIZNET5K_DEF \ + MICROPY_PY_CC3K_DEF \ // extra constants #define MICROPY_PORT_CONSTANTS \ diff --git a/stmhal/mpconfigport.mk b/stmhal/mpconfigport.mk index b5ff3af581..64145383eb 100644 --- a/stmhal/mpconfigport.mk +++ b/stmhal/mpconfigport.mk @@ -2,3 +2,6 @@ # wiznet5k module for ethernet support MICROPY_PY_WIZNET5K ?= 0 + +# cc3k module for wifi support +MICROPY_PY_CC3K ?= 0 diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h index eafa4167a3..a3a0f0d023 100644 --- a/stmhal/qstrdefsport.h +++ b/stmhal/qstrdefsport.h @@ -319,7 +319,7 @@ Q(text) Q(show) // for WIZnet5k class -#if MICROPY_HW_ENABLE_WIZNET5K +#if MICROPY_PY_WIZNET5K Q(wiznet5k) Q(WIZnet5k) Q(regs) @@ -344,6 +344,47 @@ Q(SOCK_STREAM) Q(SOCK_DGRAM) #endif +// for CC3k class +#if MICROPY_PY_CC3K +Q(cc3k) +Q(CC3k) +Q(connect) +Q(disconnect) +Q(is_connected) +Q(ifconfig) +Q(patch_version) +Q(patch_program) +Q(socket) +Q(family) +Q(type) +Q(gethostbyname) +Q(WEP) +Q(WPA) +Q(WPA2) +Q(AF_INET) +Q(AF_INET6) +Q(SOCK_STREAM) +Q(SOCK_DGRAM) +Q(SOCK_RAW) +Q(IPPROTO_IP) +Q(IPPROTO_ICMP) +Q(IPPROTO_IPV4) +Q(IPPROTO_TCP) +Q(IPPROTO_UDP) +Q(IPPROTO_IPV6) +Q(IPPROTO_RAW) +Q(send) +Q(recv) +Q(bind) +Q(listen) +Q(accept) +Q(connect) +Q(settimeout) +Q(setblocking) +Q(close) +Q(__del__) +#endif + // for stm module Q(stm) Q(mem) diff --git a/stmhal/spi.c b/stmhal/spi.c index e08c07b0ea..0b825ce1df 100644 --- a/stmhal/spi.c +++ b/stmhal/spi.c @@ -190,6 +190,14 @@ STATIC const pyb_spi_obj_t pyb_spi_obj[] = { }; #define PYB_NUM_SPI MP_ARRAY_SIZE(pyb_spi_obj) +SPI_HandleTypeDef *spi_get_handle(mp_obj_t o) { + if (!MP_OBJ_IS_TYPE(o, &pyb_spi_type)) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "expecting an SPI object")); + } + pyb_spi_obj_t *self = o; + return self->spi; +} + STATIC void pyb_spi_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) { pyb_spi_obj_t *self = self_in; diff --git a/stmhal/spi.h b/stmhal/spi.h index 3b5e0f5e5d..1f6e7e7b2d 100644 --- a/stmhal/spi.h +++ b/stmhal/spi.h @@ -31,3 +31,4 @@ extern const mp_obj_type_t pyb_spi_type; void spi_init0(void); void spi_init(SPI_HandleTypeDef *spi); +SPI_HandleTypeDef *spi_get_handle(mp_obj_t o); |