From: Alan Cox Date: Mon, 11 Jan 2016 19:04:08 +0000 (+0000) Subject: net_at: silly test stack X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=5adf4a88d7da1511d1355378b66c6d0bc6ce102c;p=FUZIX.git net_at: silly test stack The first bits of a "network" stack which implements a single offload socket driven via AT commands. It's easier to debug this and then tackle stuff like the WizNet5200 offloads and perhaps Drivewire for offload stacks. --- diff --git a/Kernel/dev/net/net_at.c b/Kernel/dev/net/net_at.c new file mode 100644 index 00000000..ad3c854e --- /dev/null +++ b/Kernel/dev/net/net_at.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include + +/* + * Implement a one socket TCP model for interfaces that provide only AT + * command emulation of ATD addr:port, ATH and carrier line. + */ + +static uint8_t at_state; + +static void netat_write(const char *p, uint16_t len) +{ + while(len--) + netat_outbyte(*p++); +} + +static void netat_write_u8ch(uint8_t v, char c) +{ + used(v); + /* FIXME: number out */ + netat_outbyte(c); +} + +static void netat_write_u16ch(uint16_t v, char c) +{ + used(v); + netat_outbyte(c); +} + +static void wakeup_all(void) +{ + wakeup(&sockets[0]); + wakeup(&sockets[0].s_data); + wakeup(&sockets[0].s_iflag); +} + +void netat_hangup(void) +{ + if (sockets[0].s_state != SS_UNUSED) { + sockets[0].s_state = SS_CLOSED; + sockets[0].s_error = EPIPE; + wakeup_all(); + } +} + +/* We read off the ready event until we get data */ + +void netat_event(void) +{ + uint8_t ch; + if (at_state == 4) { + sockets[0].s_iflag |= SI_DATA; + wakeup(&sockets[0].s_data); + netat_nowake(); + return; + } + ch = netat_byte(); + switch(at_state) { + case 0: /* Discard */ + return; + case 1: + if (ch == 'O') + at_state = 2; + else { + netat_hangup(); + at_state = 0; + } + break; + case 2: + if (ch == 'K') + at_state = 3; + else { + netat_hangup(); + at_state = 0; + } + break; + case 3: + if (ch != '\n') + break; + at_state = 4; /* Don't process */ + break; + } +} + +int net_init(struct socket *s) +{ + if (s->s_type != SOCKTYPE_TCP) { + udata.u_error = EPFNOSUPPORT; + return -1; + } + return 0; +} + +int net_bind(struct socket *s) +{ + s->s_state = SS_BOUND; + return 0; +} + +int net_listen(struct socket *s) +{ + used(s); + udata.u_error = EOPNOTSUPP; + return -1; +} + +int net_connect(struct socket *s) +{ + uint32_t n = s->s_addr[SADDR_DST].addr; + uint16_t p = s->s_addr[SADDR_DST].port; + + /* Pity drivewire won't talk addresses and ports as a hex block ! */ + netat_write("ATD ", 4); + netat_write_u8ch(n >> 24, '.'); + netat_write_u8ch(n >> 16, '.'); + netat_write_u8ch(n >> 8, '.'); + netat_write_u8ch(n, ' '); + netat_write_u16ch(p, '\n'); + /* Data ready on the channel will do the rest */ + s->s_state = SS_CONNECTING; + at_state = 1; + return 0; +} + +void net_close(struct socket *s) +{ + if (at_state == 4) { + netat_hangup(); /* Either +++ ATH with spacing, or carrier drop */ + at_state = 0; + } + s->s_state = SS_UNUSED; +} + +arg_t net_read(struct socket *s, uint8_t flag) +{ + uint16_t n = 0; + + while(1) { + if (s->s_state < SS_CONNECTED) { + udata.u_error = EINVAL; + return -1; + } + + while(netat_ready() && n < udata.u_count) { + uputc(netat_byte(), udata.u_base++); + n++; + } + if (n) + return n; + s->s_iflag &= ~SI_DATA; + netat_wake(); + /* Could do with using timeouts here to be clever for non O_NDELAY so + we aggregate data. For now assume a fifo */ + if (psleep_flags(&s->s_iflag, flag)) + return -1; + } +} + +arg_t net_write(struct socket *s, uint8_t flag) +{ + uint16_t n = 0; + + used(s); + used(flag); + + while(n < udata.u_count) { + if (sockets[0].s_state == SS_CLOSED) { + udata.u_error = EPIPE; + ssig(udata.u_ptab, SIGPIPE); + return -1; + } + /* FIXME - screen +++ handling ! */ + netat_outbyte(ugetc(udata.u_base++)); + n++; + } + return udata.u_count; +} + +struct netdevice net_dev = { + 0, + "at0", + IFF_POINTOPOINT +}; + +arg_t net_ioctl(uint8_t op, void *p) +{ + used(op); + used(p); + return -EINVAL; +} + +void netdev_init(void) +{ +} +