diff options
Diffstat (limited to 'cc3200/mods/modusocket.c')
-rw-r--r-- | cc3200/mods/modusocket.c | 244 |
1 files changed, 243 insertions, 1 deletions
diff --git a/cc3200/mods/modusocket.c b/cc3200/mods/modusocket.c index d48c474ef3..35964fa053 100644 --- a/cc3200/mods/modusocket.c +++ b/cc3200/mods/modusocket.c @@ -36,10 +36,252 @@ #include "py/stream.h" #include "netutils.h" #include "modnetwork.h" -#include "modwlan.h" #include "modusocket.h" #include "mpexception.h" +/******************************************************************************/ +// The following set of macros and functions provide a glue between the CC3100 +// simplelink layer and the functions/methods provided by the usocket module. +// They were historically in a separate file because usocket was designed to +// work with multiple NICs, and the wlan_XXX functions just provided one +// particular NIC implementation (that of the CC3100). But the CC3200 port only +// supports a single NIC (being the CC3100) so it's unnecessary and inefficient +// to provide an intermediate wrapper layer. Hence the wlan_XXX functions +// are provided below as static functions so they can be inlined directly by +// the corresponding usocket calls. + +#define WLAN_MAX_RX_SIZE 16000 +#define WLAN_MAX_TX_SIZE 1476 + +#define MAKE_SOCKADDR(addr, ip, port) SlSockAddr_t addr; \ + addr.sa_family = SL_AF_INET; \ + addr.sa_data[0] = port >> 8; \ + addr.sa_data[1] = port; \ + addr.sa_data[2] = ip[3]; \ + addr.sa_data[3] = ip[2]; \ + addr.sa_data[4] = ip[1]; \ + addr.sa_data[5] = ip[0]; + +#define UNPACK_SOCKADDR(addr, ip, port) port = (addr.sa_data[0] << 8) | addr.sa_data[1]; \ + ip[0] = addr.sa_data[5]; \ + ip[1] = addr.sa_data[4]; \ + ip[2] = addr.sa_data[3]; \ + ip[3] = addr.sa_data[2]; + +STATIC int wlan_gethostbyname(const char *name, mp_uint_t len, uint8_t *out_ip, uint8_t family) { + uint32_t ip; + int result = sl_NetAppDnsGetHostByName((_i8 *)name, (_u16)len, (_u32*)&ip, (_u8)family); + out_ip[0] = ip; + out_ip[1] = ip >> 8; + out_ip[2] = ip >> 16; + out_ip[3] = ip >> 24; + return result; +} + +STATIC int wlan_socket_socket(mod_network_socket_obj_t *s, int *_errno) { + int16_t sd = sl_Socket(s->sock_base.u_param.domain, s->sock_base.u_param.type, s->sock_base.u_param.proto); + if (sd < 0) { + *_errno = sd; + return -1; + } + s->sock_base.sd = sd; + return 0; +} + +STATIC void wlan_socket_close(mod_network_socket_obj_t *s) { + // this is to prevent the finalizer to close a socket that failed when being created + if (s->sock_base.sd >= 0) { + modusocket_socket_delete(s->sock_base.sd); + sl_Close(s->sock_base.sd); + s->sock_base.sd = -1; + } +} + +STATIC int wlan_socket_bind(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = sl_Bind(s->sock_base.sd, &addr, sizeof(addr)); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_listen(mod_network_socket_obj_t *s, mp_int_t backlog, int *_errno) { + int ret = sl_Listen(s->sock_base.sd, backlog); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_accept(mod_network_socket_obj_t *s, mod_network_socket_obj_t *s2, byte *ip, mp_uint_t *port, int *_errno) { + // accept incoming connection + int16_t sd; + SlSockAddr_t addr; + SlSocklen_t addr_len = sizeof(addr); + + sd = sl_Accept(s->sock_base.sd, &addr, &addr_len); + // save the socket descriptor + s2->sock_base.sd = sd; + if (sd < 0) { + *_errno = sd; + return -1; + } + + // return ip and port + UNPACK_SOCKADDR(addr, ip, *port); + return 0; +} + +STATIC int wlan_socket_connect(mod_network_socket_obj_t *s, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = sl_Connect(s->sock_base.sd, &addr, sizeof(addr)); + if (ret != 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_send(mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, int *_errno) { + mp_int_t bytes = 0; + if (len > 0) { + bytes = sl_Send(s->sock_base.sd, (const void *)buf, len, 0); + } + if (bytes <= 0) { + *_errno = bytes; + return -1; + } + return bytes; +} + +STATIC int wlan_socket_recv(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, int *_errno) { + int ret = sl_Recv(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0); + if (ret < 0) { + *_errno = ret; + return -1; + } + return ret; +} + +STATIC int wlan_socket_sendto( mod_network_socket_obj_t *s, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) { + MAKE_SOCKADDR(addr, ip, port) + int ret = sl_SendTo(s->sock_base.sd, (byte*)buf, len, 0, (SlSockAddr_t*)&addr, sizeof(addr)); + if (ret < 0) { + *_errno = ret; + return -1; + } + return ret; +} + +STATIC int wlan_socket_recvfrom(mod_network_socket_obj_t *s, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) { + SlSockAddr_t addr; + SlSocklen_t addr_len = sizeof(addr); + mp_int_t ret = sl_RecvFrom(s->sock_base.sd, buf, MIN(len, WLAN_MAX_RX_SIZE), 0, &addr, &addr_len); + if (ret < 0) { + *_errno = ret; + return -1; + } + UNPACK_SOCKADDR(addr, ip, *port); + return ret; +} + +STATIC int wlan_socket_setsockopt(mod_network_socket_obj_t *s, mp_uint_t level, mp_uint_t opt, const void *optval, mp_uint_t optlen, int *_errno) { + int ret = sl_SetSockOpt(s->sock_base.sd, level, opt, optval, optlen); + if (ret < 0) { + *_errno = ret; + return -1; + } + return 0; +} + +STATIC int wlan_socket_settimeout(mod_network_socket_obj_t *s, mp_uint_t timeout_s, int *_errno) { + int ret; + bool has_timeout; + if (timeout_s == 0 || timeout_s == -1) { + SlSockNonblocking_t option; + if (timeout_s == 0) { + // set non-blocking mode + option.NonblockingEnabled = 1; + } else { + // set blocking mode + option.NonblockingEnabled = 0; + } + ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING, &option, sizeof(option)); + has_timeout = false; + } else { + // set timeout + struct SlTimeval_t timeVal; + timeVal.tv_sec = timeout_s; // seconds + timeVal.tv_usec = 0; // microseconds. 10000 microseconds resolution + ret = sl_SetSockOpt(s->sock_base.sd, SL_SOL_SOCKET, SL_SO_RCVTIMEO, &timeVal, sizeof(timeVal)); + has_timeout = true; + } + + if (ret != 0) { + *_errno = ret; + return -1; + } + + s->sock_base.has_timeout = has_timeout; + return 0; +} + +STATIC int wlan_socket_ioctl (mod_network_socket_obj_t *s, mp_uint_t request, mp_uint_t arg, int *_errno) { + mp_int_t ret; + if (request == MP_STREAM_POLL) { + mp_uint_t flags = arg; + ret = 0; + int32_t sd = s->sock_base.sd; + + // init fds + SlFdSet_t rfds, wfds, xfds; + SL_FD_ZERO(&rfds); + SL_FD_ZERO(&wfds); + SL_FD_ZERO(&xfds); + + // set fds if needed + if (flags & MP_STREAM_POLL_RD) { + SL_FD_SET(sd, &rfds); + } + if (flags & MP_STREAM_POLL_WR) { + SL_FD_SET(sd, &wfds); + } + if (flags & MP_STREAM_POLL_HUP) { + SL_FD_SET(sd, &xfds); + } + + // call simplelink's select with minimum timeout + SlTimeval_t tv; + tv.tv_sec = 0; + tv.tv_usec = 1; + int32_t nfds = sl_Select(sd + 1, &rfds, &wfds, &xfds, &tv); + + // check for errors + if (nfds == -1) { + *_errno = nfds; + return -1; + } + + // check return of select + if (SL_FD_ISSET(sd, &rfds)) { + ret |= MP_STREAM_POLL_RD; + } + if (SL_FD_ISSET(sd, &wfds)) { + ret |= MP_STREAM_POLL_WR; + } + if (SL_FD_ISSET(sd, &xfds)) { + ret |= MP_STREAM_POLL_HUP; + } + } else { + *_errno = EINVAL; + ret = MP_STREAM_ERROR; + } + return ret; +} + /****************************************************************************** DEFINE PRIVATE CONSTANTS ******************************************************************************/ |