Commit 29a1ec1b authored by Damien George's avatar Damien George
Browse files

stmhal: Overhaul network drivers; has generic network protocol in C.

This patch overhauls the network driver interface.  A generic NIC must
provide a set of C-level functions to implement low-level socket control
(eg socket, bind, connect, send, recv).  Doing this, the network and
usocket modules can then use such a NIC to implement proper socket
control at the Python level.

This patch also updates the CC3K and WIZNET5K drivers to conform to the
new interface, and fixes some bugs in the drivers.  They now work
reasonably well.
parent d8f23926
......@@ -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 \
......
......@@ -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"));
......
......@@ -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);
......@@ -61,11 +61,30 @@
#include "netapp.h"
#include "patch_prog.h"
/// \moduleref network
#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)
int CC3000_EXPORT(errno); // for cc3000 driver
#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);
STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol, int *_errno);
int CC3000_EXPORT(errno); // for cc3000 driver
STATIC volatile uint32_t fd_closed_state = 0;
STATIC volatile bool wlan_connected = false;
......@@ -103,27 +122,14 @@ STATIC void cc3k_callback(long event_type, char *data, unsigned char length) {
}
}
STATIC mp_obj_t cc3k_socket(mp_obj_t nic, int domain, int type, int fileno, int *_errno) {
switch (domain) {
case MOD_NETWORK_AF_INET: domain = AF_INET; break;
case MOD_NETWORK_AF_INET6: domain = AF_INET6; break;
default: *_errno = EAFNOSUPPORT; return MP_OBJ_NULL;
}
switch (type) {
case MOD_NETWORK_SOCK_STREAM: type = SOCK_STREAM; break;
case MOD_NETWORK_SOCK_DGRAM: type = SOCK_DGRAM; break;
case MOD_NETWORK_SOCK_RAW: type = SOCK_RAW; break;
default: *_errno = EINVAL; return MP_OBJ_NULL;
}
return cc3k_socket_new(domain, type, 0, _errno);
}
STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uint8_t *out_ip) {
uint32_t ip;
if (CC3000_EXPORT(gethostbyname)((char*)name, len, &ip) < 0) {
return CC3000_EXPORT(errno);
// 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) {
......@@ -139,17 +145,289 @@ STATIC int cc3k_gethostbyname(mp_obj_t nic, const char *name, mp_uint_t len, uin
return 0;
}
/******************************************************************************/
// Micro Python bindings; CC3k class
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);
/// \class CC3k - driver for CC3000 Wifi modules
// 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.
// \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)
......@@ -173,8 +451,7 @@ STATIC mp_obj_t cc3k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw
ReadWlanInterruptPin, SpiResumeSpi, SpiPauseSpi, WriteWlanPin);
if (wlan_start(0) != 0) {
nlr_raise(mp_obj_new_exception_msg(
&mp_type_OSError, "Failed to init wlan module"));
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
......@@ -195,7 +472,7 @@ STATIC mp_obj_t cc3k_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw
return cc3k;
}
/// \method connect(ssid, key=None, *, security=WPA2, bssid=None)
// 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} },
......@@ -237,46 +514,44 @@ STATIC mp_obj_t cc3k_connect(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
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);
// 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_is_connected(mp_obj_t self_in) {
if (wlan_connected && ip_obtained) {
return mp_const_true;
}
return mp_const_false;
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_is_connected_obj, cc3k_is_connected);
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={{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];
tNetappIpconfigRetArgs ipconfig;
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;
// 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);
......@@ -297,7 +572,7 @@ STATIC mp_obj_t cc3k_patch_program(mp_obj_t self_in, mp_obj_t 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");
printf("pass 'pgm' as argument in order to program\n");
}
return mp_const_none;