Skip to content

Commit f90b59e

Browse files
committed
stmhal, modcc3k: Add ioctl to cc3k sockets so select works.
1 parent 133b083 commit f90b59e

1 file changed

Lines changed: 87 additions & 124 deletions

File tree

stmhal/modcc3k.c

Lines changed: 87 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@
2727
// We can't include stdio.h because it defines _types_fd_set, but we
2828
// need to use the CC3000 version of this type.
2929

30-
// We can't include errno.h because CC3000 defines its own errnos.
31-
// (And they are different to the standard ones!)
32-
3330
#include <std.h>
3431
#include <string.h>
32+
#include <stdarg.h>
33+
#include <errno.h>
34+
35+
// CC3000 defines its own ENOBUFS (different to standard one!)
36+
// CC3000 uses global variable called errno
37+
#undef ENOBUFS
38+
#undef errno
3539

3640
#include "stm32f4xx_hal.h"
3741
#include "mpconfig.h"
@@ -45,6 +49,7 @@
4549
#include "pin.h"
4650
#include "genhdr/pins.h"
4751
#include "spi.h"
52+
#include "pybioctl.h"
4853

4954
#include "hci.h"
5055
#include "socket.h"
@@ -61,17 +66,20 @@ STATIC const mp_obj_type_t cc3k_socket_type;
6166

6267
STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t protocol);
6368

64-
STATIC volatile uint32_t fd_state = 0;
69+
STATIC volatile uint32_t fd_closed_state = 0;
6570
STATIC volatile bool wlan_connected = false;
6671
STATIC volatile bool ip_obtained = false;
6772

68-
STATIC int cc3k_get_fd_state(int fd) {
69-
return (fd_state & (1<<fd));
73+
STATIC int cc3k_get_fd_closed_state(int fd) {
74+
return fd_closed_state & (1 << fd);
7075
}
7176

72-
STATIC void cc3k_clear_fd_state(int fd) {
73-
// reset socket state
74-
fd_state &= ~(1<<fd);
77+
STATIC void cc3k_set_fd_closed_state(int fd) {
78+
fd_closed_state |= 1 << fd;
79+
}
80+
81+
STATIC void cc3k_reset_fd_closed_state(int fd) {
82+
fd_closed_state &= ~(1 << fd);
7583
}
7684

7785
STATIC void cc3k_callback(long event_type, char *data, unsigned char length) {
@@ -89,7 +97,7 @@ STATIC void cc3k_callback(long event_type, char *data, unsigned char length) {
8997
break;
9098
case HCI_EVNT_BSD_TCP_CLOSE_WAIT:
9199
// mark socket for closure
92-
fd_state |= (1<<((uint8_t)data[0]));
100+
cc3k_set_fd_closed_state(data[0]);
93101
break;
94102
}
95103
}
@@ -338,8 +346,6 @@ STATIC const mp_obj_type_t cc3k_type = {
338346
/******************************************************************************/
339347
// Micro Python bindings; CC3k socket class
340348

341-
#define EPIPE (32)
342-
//#define MAX_FD (8)
343349
#define MAX_ADDRSTRLEN (128)
344350
#define MAX_RX_PACKET (CC3000_RX_BUFFER_SIZE-CC3000_MINIMAL_RX_SIZE-1)
345351
#define MAX_TX_PACKET (CC3000_TX_BUFFER_SIZE-CC3000_MINIMAL_TX_SIZE-1)
@@ -362,7 +368,7 @@ STATIC mp_obj_t cc3k_socket_new(mp_uint_t family, mp_uint_t type, mp_uint_t prot
362368
}
363369

364370
// clear socket state
365-
cc3k_clear_fd_state(s->fd);
371+
cc3k_reset_fd_closed_state(s->fd);
366372

367373
return s;
368374
}
@@ -375,7 +381,7 @@ STATIC void cc3k_socket_print(void (*print)(void *env, const char *fmt, ...), vo
375381
STATIC mp_uint_t cc3k_socket_send(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
376382
cc3k_socket_obj_t *self = self_in;
377383

378-
if (cc3k_get_fd_state(self->fd)) {
384+
if (cc3k_get_fd_closed_state(self->fd)) {
379385
closesocket(self->fd);
380386
*errcode = EPIPE;
381387
return 0;
@@ -401,7 +407,7 @@ STATIC mp_uint_t cc3k_socket_send(mp_obj_t self_in, const void *buf, mp_uint_t s
401407
STATIC mp_uint_t cc3k_socket_recv(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
402408
cc3k_socket_obj_t *self = self_in;
403409

404-
if (cc3k_get_fd_state(self->fd)) {
410+
if (cc3k_get_fd_closed_state(self->fd)) {
405411
closesocket(self->fd);
406412
return 0;
407413
}
@@ -475,7 +481,7 @@ STATIC mp_obj_t cc3k_socket_accept(mp_obj_t self_in) {
475481
}
476482

477483
// clear socket state
478-
cc3k_clear_fd_state(fd);
484+
cc3k_reset_fd_closed_state(fd);
479485

480486
// create new socket object
481487
cc3k_socket_obj_t *socket_obj = m_new_obj_with_finaliser(cc3k_socket_obj_t);
@@ -587,9 +593,74 @@ STATIC const mp_map_elem_t cc3k_socket_locals_dict_table[] = {
587593

588594
STATIC MP_DEFINE_CONST_DICT(cc3k_socket_locals_dict, cc3k_socket_locals_dict_table);
589595

596+
mp_uint_t cc3k_ioctl(mp_obj_t self_in, mp_uint_t request, int *errcode, ...) {
597+
cc3k_socket_obj_t *self = self_in;
598+
va_list vargs;
599+
va_start(vargs, errcode);
600+
mp_uint_t ret;
601+
if (request == MP_IOCTL_POLL) {
602+
mp_uint_t flags = va_arg(vargs, mp_uint_t);
603+
ret = 0;
604+
int fd = self->fd;
605+
606+
// init fds
607+
fd_set rfds, wfds, xfds;
608+
FD_ZERO(&rfds);
609+
FD_ZERO(&wfds);
610+
FD_ZERO(&xfds);
611+
612+
// set fds if needed
613+
if (flags & MP_IOCTL_POLL_RD) {
614+
FD_SET(fd, &rfds);
615+
616+
// A socked that just closed is available for reading. A call to
617+
// recv() returns 0 which is consistent with BSD.
618+
if (cc3k_get_fd_closed_state(fd)) {
619+
ret |= MP_IOCTL_POLL_RD;
620+
}
621+
}
622+
if (flags & MP_IOCTL_POLL_WR) {
623+
FD_SET(fd, &wfds);
624+
}
625+
if (flags & MP_IOCTL_POLL_HUP) {
626+
FD_SET(fd, &xfds);
627+
}
628+
629+
// call cc3000 select with minimum timeout
630+
timeval tv;
631+
tv.tv_sec = 0;
632+
tv.tv_usec = 1;
633+
int nfds = select(fd + 1, &rfds, &wfds, &xfds, &tv);
634+
635+
// check for error
636+
if (nfds == -1) {
637+
*errcode = errno; // return cc3000's errno
638+
return -1;
639+
}
640+
641+
// check return of select
642+
if (FD_ISSET(fd, &rfds)) {
643+
ret |= MP_IOCTL_POLL_RD;
644+
}
645+
if (FD_ISSET(fd, &wfds)) {
646+
ret |= MP_IOCTL_POLL_WR;
647+
}
648+
if (FD_ISSET(fd, &xfds)) {
649+
ret |= MP_IOCTL_POLL_HUP;
650+
}
651+
} else {
652+
*errcode = EINVAL;
653+
ret = -1;
654+
}
655+
va_end(vargs);
656+
return ret;
657+
}
658+
590659
STATIC const mp_stream_p_t cc3k_socket_stream_p = {
591660
.read = cc3k_socket_recv,
592661
.write = cc3k_socket_send,
662+
.ioctl = cc3k_ioctl,
663+
.is_text = false,
593664
};
594665

595666
STATIC const mp_obj_type_t cc3k_socket_type = {
@@ -602,114 +673,6 @@ STATIC const mp_obj_type_t cc3k_socket_type = {
602673
.locals_dict = (mp_obj_t)&cc3k_socket_locals_dict,
603674
};
604675

605-
// the following code is for select, which is yet to be implemented
606-
#if 0
607-
#define MP_ASSERT_TYPE(obj, type) \
608-
do { \
609-
__typeof__ (obj) _a = (obj); \
610-
__typeof__ (type) _b = (type); \
611-
if (!MP_OBJ_IS_TYPE(_a, _b)) { \
612-
nlr_jump(mp_obj_new_exception_msg_varg( \
613-
&mp_type_TypeError, \
614-
"can't convert %s to %s", \
615-
mp_obj_get_type_str(_a), \
616-
_b->name)); \
617-
} \
618-
} while(0)
619-
620-
// select helper functions
621-
STATIC void set_fds(int *nfds, mp_obj_t *fdlist, mp_uint_t fdlist_len, fd_set *fdset) {
622-
623-
// clear fd set
624-
FD_ZERO(fdset);
625-
626-
// add sockets to fd set
627-
for (int i=0; i<fdlist_len; i++) {
628-
socket_t *s = fdlist[i];
629-
630-
// check arg type
631-
MP_ASSERT_TYPE(s, &cc3k_socket_type);
632-
633-
// add to fd set
634-
FD_SET(s->fd, fdset);
635-
636-
if (s->fd > (*nfds)) {
637-
*nfds = s->fd;
638-
}
639-
}
640-
}
641-
642-
STATIC void get_fds(mp_obj_t *fdlist, mp_uint_t fdlist_len, mp_obj_t *fdlist_out, fd_set *fdset) {
643-
for (int i=0; i<fdlist_len; i++) {
644-
socket_t *s = fdlist[i];
645-
if (FD_ISSET(s->fd, fdset)) {
646-
socket_t *socket_obj = m_new_obj_with_finaliser(socket_t);
647-
socket_obj->base.type = (mp_obj_t)&socket_type;
648-
socket_obj->fd = s->fd;
649-
mp_obj_list_append(fdlist_out, socket_obj);
650-
}
651-
}
652-
}
653-
654-
STATIC mp_obj_t cc3k_select(mp_uint_t n_args, const mp_obj_t *args) {
655-
int nfds=0; //highest-numbered fd plus 1
656-
timeval tv={0};
657-
fd_set rfds, wfds, xfds;
658-
659-
mp_obj_t *rlist, *wlist, *xlist;
660-
mp_uint_t rlist_len, wlist_len, xlist_len;
661-
662-
// read args
663-
mp_obj_get_array(args[0], &rlist_len, &rlist);
664-
mp_obj_get_array(args[1], &wlist_len, &wlist);
665-
mp_obj_get_array(args[2], &xlist_len, &xlist);
666-
667-
if (n_args == 4) {
668-
float timeout = mp_obj_get_float(args[3]);
669-
tv.tv_sec = (int)timeout;
670-
tv.tv_usec = (timeout-(int)timeout)*1000*1000;
671-
}
672-
673-
// add fds to their respective sets
674-
set_fds(&nfds, rlist, rlist_len, &rfds);
675-
set_fds(&nfds, wlist, wlist_len, &wfds);
676-
set_fds(&nfds, xlist, xlist_len, &xfds);
677-
678-
// call select
679-
nfds = select(nfds+1, &rfds, &wfds, &xfds, &tv);
680-
681-
// if any of the read sockets is closed, we add it to the read fd set,
682-
// a subsequent call to recv() returns 0. This behavior is consistent with BSD.
683-
for (int i=0; i<rlist_len; i++) {
684-
socket_t *s = rlist[i];
685-
if (cc3k_get_fd_state(s->fd)) {
686-
FD_SET(s->fd, &rfds);
687-
nfds = (nfds > s->fd)? nfds:s->fd;
688-
}
689-
}
690-
691-
// return value; a tuple of 3 lists
692-
mp_obj_t fds[3] = {
693-
mp_obj_new_list(0, NULL),
694-
mp_obj_new_list(0, NULL),
695-
mp_obj_new_list(0, NULL)
696-
};
697-
698-
// On success, select() returns the number of file descriptors contained
699-
// in the three returned descriptor sets which may be zero if the timeout
700-
// expires before anything interesting happens, -1 is returned on error.
701-
if (nfds == -1) { // select failed
702-
nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "select failed"));
703-
} else if (nfds) { // an fd is ready
704-
get_fds(rlist, rlist_len, fds[0], &rfds);
705-
get_fds(wlist, wlist_len, fds[1], &wfds);
706-
get_fds(xlist, xlist_len, fds[2], &xfds);
707-
} // select timedout
708-
709-
return mp_obj_new_tuple(3, fds);
710-
}
711-
#endif
712-
713676
/******************************************************************************/
714677
// Micro Python bindings; CC3k module
715678

0 commit comments

Comments
 (0)