Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested

Dependents:   STM32F746_iothub_client_sample_mqtt DISCO-F746NG_Ethernet Nucleo_F746ZG_Ethernet thethingsiO-DISCO_F746NG-mqtt ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers slipif.c Source File

slipif.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * SLIP Interface
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved. 
00010  *
00011  * Redistribution and use in source and binary forms, with or without 
00012  * modification, are permitted provided that the following conditions 
00013  * are met: 
00014  * 1. Redistributions of source code must retain the above copyright 
00015  *    notice, this list of conditions and the following disclaimer. 
00016  * 2. Redistributions in binary form must reproduce the above copyright 
00017  *    notice, this list of conditions and the following disclaimer in the 
00018  *    documentation and/or other materials provided with the distribution. 
00019  * 3. Neither the name of the Institute nor the names of its contributors 
00020  *    may be used to endorse or promote products derived from this software 
00021  *    without specific prior written permission. 
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00033  * SUCH DAMAGE. 
00034  *
00035  * This file is built upon the file: src/arch/rtxc/netif/sioslip.c
00036  *
00037  * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com> 
00038  *         Simon Goldschmidt
00039  *
00040  * Usage: This netif can be used in three ways:
00041  *        1) For NO_SYS==0, an RX thread can be used which blocks on sio_read()
00042  *           until data is received.
00043  *        2) In your main loop, call slipif_poll() to check for new RX bytes,
00044  *           completed packets are fed into netif->input().
00045  *        3) Call slipif_received_byte[s]() from your serial RX ISR and
00046  *           slipif_process_rxqueue() from your main loop. ISR level decodes
00047  *           packets and puts completed packets on a queue which is fed into
00048  *           the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for
00049  *           pbuf_alloc to work on ISR level!).
00050  *     
00051  */
00052 
00053 /* 
00054  * This is an arch independent SLIP netif. The specific serial hooks must be
00055  * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
00056  */
00057 
00058 #include "netif/slipif.h"
00059 #include "lwip/opt.h"
00060 
00061 #if LWIP_HAVE_SLIPIF
00062 
00063 #include "lwip/def.h"
00064 #include "lwip/pbuf.h"
00065 #include "lwip/stats.h"
00066 #include "lwip/snmp.h"
00067 #include "lwip/sio.h"
00068 #include "lwip/sys.h"
00069 
00070 #define SLIP_END     0xC0 /* 0300: start and end of every packet */
00071 #define SLIP_ESC     0xDB /* 0333: escape start (one byte escaped data follows) */
00072 #define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */
00073 #define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */
00074 
00075 /** Maximum packet size that is received by this netif */
00076 #ifndef SLIP_MAX_SIZE
00077 #define SLIP_MAX_SIZE 1500
00078 #endif
00079 
00080 /** Define this to the interface speed for SNMP
00081  * (sio_fd is the sio_fd_t returned by sio_open).
00082  * The default value of zero means 'unknown'.
00083  */
00084 #ifndef SLIP_SIO_SPEED
00085 #define SLIP_SIO_SPEED(sio_fd) 0
00086 #endif
00087 
00088 enum slipif_recv_state {
00089     SLIP_RECV_NORMAL,
00090     SLIP_RECV_ESCAPE,
00091 };
00092 
00093 struct slipif_priv {
00094   sio_fd_t sd;
00095   /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
00096   struct pbuf *p, *q;
00097   u8_t state;
00098   u16_t i, recved;
00099 #if SLIP_RX_FROM_ISR
00100   struct pbuf *rxpackets;
00101 #endif
00102 };
00103 
00104 /**
00105  * Send a pbuf doing the necessary SLIP encapsulation
00106  *
00107  * Uses the serial layer's sio_send()
00108  *
00109  * @param netif the lwip network interface structure for this slipif
00110  * @param p the pbuf chaing packet to send
00111  * @param ipaddr the ip address to send the packet to (not used for slipif)
00112  * @return always returns ERR_OK since the serial layer does not provide return values
00113  */
00114 err_t
00115 slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
00116 {
00117   struct slipif_priv *priv;
00118   struct pbuf *q;
00119   u16_t i;
00120   u8_t c;
00121 
00122   LWIP_ASSERT("netif != NULL", (netif != NULL));
00123   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
00124   LWIP_ASSERT("p != NULL", (p != NULL));
00125 
00126   LWIP_UNUSED_ARG(ipaddr);
00127 
00128   LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len));
00129   priv = netif->state;
00130 
00131   /* Send pbuf out on the serial I/O device. */
00132   /* Start with packet delimiter. */
00133   sio_send(SLIP_END, priv->sd);
00134 
00135   for (q = p; q != NULL; q = q->next) {
00136     for (i = 0; i < q->len; i++) {
00137       c = ((u8_t *)q->payload)[i];
00138       switch (c) {
00139       case SLIP_END:
00140         /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */
00141         sio_send(SLIP_ESC, priv->sd);
00142         sio_send(SLIP_ESC_END, priv->sd);
00143         break;
00144       case SLIP_ESC:
00145         /* need to escape this byte (0xDB -> 0xDB, 0xDD) */
00146         sio_send(SLIP_ESC, priv->sd);
00147         sio_send(SLIP_ESC_ESC, priv->sd);
00148         break;
00149       default:
00150         /* normal byte - no need for escaping */
00151         sio_send(c, priv->sd);
00152         break;
00153       }
00154     }
00155   }
00156   /* End with packet delimiter. */
00157   sio_send(SLIP_END, priv->sd);
00158   return ERR_OK;
00159 }
00160 
00161 /**
00162  * Handle the incoming SLIP stream character by character
00163  *
00164  * @param netif the lwip network interface structure for this slipif
00165  * @param c received character (multiple calls to this function will
00166  *        return a complete packet, NULL is returned before - used for polling)
00167  * @return The IP packet when SLIP_END is received
00168  */
00169 static struct pbuf*
00170 slipif_rxbyte(struct netif *netif, u8_t c)
00171 {
00172   struct slipif_priv *priv;
00173   struct pbuf *t;
00174 
00175   LWIP_ASSERT("netif != NULL", (netif != NULL));
00176   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
00177 
00178   priv = netif->state;
00179 
00180   switch (priv->state) {
00181   case SLIP_RECV_NORMAL:
00182     switch (c) {
00183     case SLIP_END:
00184       if (priv->recved > 0) {
00185         /* Received whole packet. */
00186         /* Trim the pbuf to the size of the received packet. */
00187         pbuf_realloc(priv->q, priv->recved);
00188 
00189         LINK_STATS_INC(link.recv);
00190 
00191         LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved));
00192         t = priv->q;
00193         priv->p = priv->q = NULL;
00194         priv->i = priv->recved = 0;
00195         return t;
00196       }
00197       return NULL;
00198     case SLIP_ESC:
00199       priv->state = SLIP_RECV_ESCAPE;
00200       return NULL;
00201     } /* end switch (c) */
00202     break;
00203   case SLIP_RECV_ESCAPE:
00204     /* un-escape END or ESC bytes, leave other bytes
00205        (although that would be a protocol error) */
00206     switch (c) {
00207     case SLIP_ESC_END:
00208       c = SLIP_END;
00209       break;
00210     case SLIP_ESC_ESC:
00211       c = SLIP_ESC;
00212       break;
00213     }
00214     priv->state = SLIP_RECV_NORMAL;
00215     break;
00216   } /* end switch (priv->state) */
00217 
00218   /* byte received, packet not yet completely received */
00219   if (priv->p == NULL) {
00220     /* allocate a new pbuf */
00221     LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
00222     priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL);
00223 
00224     if (priv->p == NULL) {
00225       LINK_STATS_INC(link.drop);
00226       LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
00227       /* don't process any further since we got no pbuf to receive to */
00228       return NULL;
00229     }
00230 
00231     if (priv->q != NULL) {
00232       /* 'chain' the pbuf to the existing chain */
00233       pbuf_cat(priv->q, priv->p);
00234     } else {
00235       /* p is the first pbuf in the chain */
00236       priv->q = priv->p;
00237     }
00238   }
00239 
00240   /* this automatically drops bytes if > SLIP_MAX_SIZE */
00241   if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
00242     ((u8_t *)priv->p->payload)[priv->i] = c;
00243     priv->recved++;
00244     priv->i++;
00245     if (priv->i >= priv->p->len) {
00246       /* on to the next pbuf */
00247       priv->i = 0;
00248       if (priv->p->next != NULL && priv->p->next->len > 0) {
00249         /* p is a chain, on to the next in the chain */
00250           priv->p = priv->p->next;
00251       } else {
00252         /* p is a single pbuf, set it to NULL so next time a new
00253          * pbuf is allocated */
00254           priv->p = NULL;
00255       }
00256     }
00257   }
00258   return NULL;
00259 }
00260 
00261 /** Like slipif_rxbyte, but passes completed packets to netif->input
00262  *
00263  * @param netif The lwip network interface structure for this slipif
00264  * @param data received character
00265  */
00266 static void
00267 slipif_rxbyte_input(struct netif *netif, u8_t c)
00268 {
00269   struct pbuf *p;
00270   p = slipif_rxbyte(netif, c);
00271   if (p != NULL) {
00272     if (netif->input(p, netif) != ERR_OK) {
00273       pbuf_free(p);
00274     }
00275   }
00276 }
00277 
00278 #if SLIP_USE_RX_THREAD
00279 /**
00280  * The SLIP input thread.
00281  *
00282  * Feed the IP layer with incoming packets
00283  *
00284  * @param nf the lwip network interface structure for this slipif
00285  */
00286 static void
00287 slipif_loop_thread(void *nf)
00288 {
00289   u8_t c;
00290   struct netif *netif = (struct netif *)nf;
00291   struct slipif_priv *priv = (struct slipif_priv *)netif->state;
00292 
00293   while (1) {
00294     if (sio_read(priv->sd, &c, 1) > 0) {
00295       slipif_rxbyte_input(netif, c);
00296     }
00297   }
00298 }
00299 #endif /* SLIP_USE_RX_THREAD */
00300 
00301 /**
00302  * SLIP netif initialization
00303  *
00304  * Call the arch specific sio_open and remember
00305  * the opened device in the state field of the netif.
00306  *
00307  * @param netif the lwip network interface structure for this slipif
00308  * @return ERR_OK if serial line could be opened,
00309  *         ERR_MEM if no memory could be allocated,
00310  *         ERR_IF is serial line couldn't be opened
00311  *
00312  * @note netif->num must contain the number of the serial port to open
00313  *       (0 by default). If netif->state is != NULL, it is interpreted as an
00314  *       u8_t pointer pointing to the serial port number instead of netif->num.
00315  *
00316  */
00317 err_t
00318 slipif_init(struct netif *netif)
00319 {
00320   struct slipif_priv *priv;
00321   u8_t sio_num;
00322 
00323   LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));
00324 
00325   /* Allocate private data */
00326   priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv));
00327   if (!priv) {
00328     return ERR_MEM;
00329   }
00330 
00331   netif->name[0] = 's';
00332   netif->name[1] = 'l';
00333   netif->output = slipif_output;
00334   netif->mtu = SLIP_MAX_SIZE;
00335   netif->flags |= NETIF_FLAG_POINTTOPOINT;
00336 
00337   /* netif->state or netif->num contain the port number */
00338   if (netif->state != NULL) {
00339     sio_num = *(u8_t*)netif->state;
00340   } else {
00341     sio_num = netif->num;
00342   }
00343   /* Try to open the serial port. */
00344   priv->sd = sio_open(sio_num);
00345   if (!priv->sd) {
00346     /* Opening the serial port failed. */
00347     mem_free(priv);
00348     return ERR_IF;
00349   }
00350 
00351   /* Initialize private data */
00352   priv->p = NULL;
00353   priv->q = NULL;
00354   priv->state = SLIP_RECV_NORMAL;
00355   priv->i = 0;
00356   priv->recved = 0;
00357 #if SLIP_RX_FROM_ISR
00358   priv->rxpackets = NULL;
00359 #endif
00360 
00361   netif->state = priv;
00362 
00363   /* initialize the snmp variables and counters inside the struct netif */
00364   NETIF_INIT_SNMP(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd));
00365 
00366 #if SLIP_USE_RX_THREAD
00367   /* Create a thread to poll the serial line. */
00368   sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
00369     SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
00370 #endif /* SLIP_USE_RX_THREAD */
00371   return ERR_OK;
00372 }
00373 
00374 /**
00375  * Polls the serial device and feeds the IP layer with incoming packets.
00376  *
00377  * @param netif The lwip network interface structure for this slipif
00378  */
00379 void
00380 slipif_poll(struct netif *netif)
00381 {
00382   u8_t c;
00383   struct slipif_priv *priv;
00384 
00385   LWIP_ASSERT("netif != NULL", (netif != NULL));
00386   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
00387 
00388   priv = (struct slipif_priv *)netif->state;
00389 
00390   while (sio_tryread(priv->sd, &c, 1) > 0) {
00391     slipif_rxbyte_input(netif, c);
00392   }
00393 }
00394 
00395 #if SLIP_RX_FROM_ISR
00396 /**
00397  * Feeds the IP layer with incoming packets that were receive
00398  *
00399  * @param netif The lwip network interface structure for this slipif
00400  */
00401 void
00402 slipif_process_rxqueue(struct netif *netif)
00403 {
00404   struct slipif_priv *priv;
00405   SYS_ARCH_DECL_PROTECT(old_level);
00406 
00407   LWIP_ASSERT("netif != NULL", (netif != NULL));
00408   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
00409 
00410   priv = (struct slipif_priv *)netif->state;
00411 
00412   SYS_ARCH_PROTECT(old_level);
00413   while (priv->rxpackets != NULL) {
00414     struct pbuf *p = priv->rxpackets;
00415 #if SLIP_RX_QUEUE
00416     /* dequeue packet */
00417     struct pbuf *q = p;
00418     while ((q->len != q->tot_len) && (q->next != NULL)) {
00419       q = q->next;
00420     }
00421     priv->rxpackets = q->next;
00422     q->next = NULL;
00423 #else /* SLIP_RX_QUEUE */
00424     priv->rxpackets = NULL;
00425 #endif /* SLIP_RX_QUEUE */
00426     SYS_ARCH_UNPROTECT(old_level);
00427     if (netif->input(p, netif) != ERR_OK) {
00428       pbuf_free(p);
00429     }
00430     SYS_ARCH_PROTECT(old_level);
00431   }
00432 }
00433 
00434 /** Like slipif_rxbyte, but queues completed packets.
00435  *
00436  * @param netif The lwip network interface structure for this slipif
00437  * @param data Received serial byte
00438  */
00439 static void
00440 slipif_rxbyte_enqueue(struct netif *netif, u8_t data)
00441 {
00442   struct pbuf *p;
00443   struct slipif_priv *priv = (struct slipif_priv *)netif->state;
00444   SYS_ARCH_DECL_PROTECT(old_level);
00445 
00446   p = slipif_rxbyte(netif, data);
00447   if (p != NULL) {
00448     SYS_ARCH_PROTECT(old_level);
00449     if (priv->rxpackets != NULL) {
00450 #if SLIP_RX_QUEUE
00451       /* queue multiple pbufs */
00452       struct pbuf *q = p;
00453       while(q->next != NULL) {
00454         q = q->next;
00455       }
00456       q->next = p;
00457     } else {
00458 #else /* SLIP_RX_QUEUE */
00459       pbuf_free(priv->rxpackets);
00460     }
00461     {
00462 #endif /* SLIP_RX_QUEUE */
00463       priv->rxpackets = p;
00464     }
00465     SYS_ARCH_UNPROTECT(old_level);
00466   }
00467 }
00468 
00469 /**
00470  * Process a received byte, completed packets are put on a queue that is
00471  * fed into IP through slipif_process_rxqueue().
00472  *
00473  * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
00474  *
00475  * @param netif The lwip network interface structure for this slipif
00476  * @param data received character
00477  */
00478 void
00479 slipif_received_byte(struct netif *netif, u8_t data)
00480 {
00481   LWIP_ASSERT("netif != NULL", (netif != NULL));
00482   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
00483   slipif_rxbyte_enqueue(netif, data);
00484 }
00485 
00486 /**
00487  * Process multiple received byte, completed packets are put on a queue that is
00488  * fed into IP through slipif_process_rxqueue().
00489  *
00490  * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
00491  *
00492  * @param netif The lwip network interface structure for this slipif
00493  * @param data received character
00494  * @param len Number of received characters
00495  */
00496 void
00497 slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len)
00498 {
00499   u8_t i;
00500   u8_t *rxdata = data;
00501   LWIP_ASSERT("netif != NULL", (netif != NULL));
00502   LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
00503 
00504   for (i = 0; i < len; i++, rxdata++) {
00505     slipif_rxbyte_enqueue(netif, *rxdata);
00506   }
00507 }
00508 #endif /* SLIP_RX_FROM_ISR */
00509 
00510 #endif /* LWIP_HAVE_SLIPIF */