Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-os by
lwip_slipif.c
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 00041 00042 /** 00043 * @defgroup slipif SLIP netif 00044 * @ingroup addons 00045 * 00046 * This is an arch independent SLIP netif. The specific serial hooks must be 00047 * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send 00048 * 00049 * Usage: This netif can be used in three ways:\n 00050 * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() 00051 * until data is received.\n 00052 * 2) In your main loop, call slipif_poll() to check for new RX bytes, 00053 * completed packets are fed into netif->input().\n 00054 * 3) Call slipif_received_byte[s]() from your serial RX ISR and 00055 * slipif_process_rxqueue() from your main loop. ISR level decodes 00056 * packets and puts completed packets on a queue which is fed into 00057 * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for 00058 * pbuf_alloc to work on ISR level!). 00059 * 00060 */ 00061 00062 #include "netif/slipif.h" 00063 #include "lwip/opt.h" 00064 00065 #include "lwip/def.h" 00066 #include "lwip/pbuf.h" 00067 #include "lwip/stats.h" 00068 #include "lwip/snmp.h" 00069 #include "lwip/sys.h" 00070 #include "lwip/sio.h" 00071 00072 #define SLIP_END 0xC0 /* 0300: start and end of every packet */ 00073 #define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */ 00074 #define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */ 00075 #define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */ 00076 00077 /** Maximum packet size that is received by this netif */ 00078 #ifndef SLIP_MAX_SIZE 00079 #define SLIP_MAX_SIZE 1500 00080 #endif 00081 00082 /** Define this to the interface speed for SNMP 00083 * (sio_fd is the sio_fd_t returned by sio_open). 00084 * The default value of zero means 'unknown'. 00085 */ 00086 #ifndef SLIP_SIO_SPEED 00087 #define SLIP_SIO_SPEED(sio_fd) 0 00088 #endif 00089 00090 enum slipif_recv_state { 00091 SLIP_RECV_NORMAL, 00092 SLIP_RECV_ESCAPE 00093 }; 00094 00095 struct slipif_priv { 00096 sio_fd_t sd; 00097 /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ 00098 struct pbuf *p, *q; 00099 u8_t state; 00100 u16_t i, recved; 00101 #if SLIP_RX_FROM_ISR 00102 struct pbuf *rxpackets; 00103 #endif 00104 }; 00105 00106 /** 00107 * Send a pbuf doing the necessary SLIP encapsulation 00108 * 00109 * Uses the serial layer's sio_send() 00110 * 00111 * @param netif the lwip network interface structure for this slipif 00112 * @param p the pbuf chain packet to send 00113 * @return always returns ERR_OK since the serial layer does not provide return values 00114 */ 00115 static err_t 00116 slipif_output(struct netif *netif, struct pbuf *p) 00117 { 00118 struct slipif_priv *priv; 00119 struct pbuf *q; 00120 u16_t i; 00121 u8_t c; 00122 00123 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00124 LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); 00125 LWIP_ASSERT("p != NULL", (p != NULL)); 00126 00127 LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len)); 00128 priv = (struct slipif_priv *)netif->state; 00129 00130 /* Send pbuf out on the serial I/O device. */ 00131 /* Start with packet delimiter. */ 00132 sio_send(SLIP_END, priv->sd); 00133 00134 for (q = p; q != NULL; q = q->next) { 00135 for (i = 0; i < q->len; i++) { 00136 c = ((u8_t *)q->payload)[i]; 00137 switch (c) { 00138 case SLIP_END: 00139 /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */ 00140 sio_send(SLIP_ESC, priv->sd); 00141 sio_send(SLIP_ESC_END, priv->sd); 00142 break; 00143 case SLIP_ESC: 00144 /* need to escape this byte (0xDB -> 0xDB, 0xDD) */ 00145 sio_send(SLIP_ESC, priv->sd); 00146 sio_send(SLIP_ESC_ESC, priv->sd); 00147 break; 00148 default: 00149 /* normal byte - no need for escaping */ 00150 sio_send(c, priv->sd); 00151 break; 00152 } 00153 } 00154 } 00155 /* End with packet delimiter. */ 00156 sio_send(SLIP_END, priv->sd); 00157 return ERR_OK; 00158 } 00159 00160 #if LWIP_IPV4 00161 /** 00162 * Send a pbuf doing the necessary SLIP encapsulation 00163 * 00164 * Uses the serial layer's sio_send() 00165 * 00166 * @param netif the lwip network interface structure for this slipif 00167 * @param p the pbuf chain packet to send 00168 * @param ipaddr the ip address to send the packet to (not used for slipif) 00169 * @return always returns ERR_OK since the serial layer does not provide return values 00170 */ 00171 static err_t 00172 slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr) 00173 { 00174 LWIP_UNUSED_ARG(ipaddr); 00175 return slipif_output(netif, p); 00176 } 00177 #endif /* LWIP_IPV4 */ 00178 00179 #if LWIP_IPV6 00180 /** 00181 * Send a pbuf doing the necessary SLIP encapsulation 00182 * 00183 * Uses the serial layer's sio_send() 00184 * 00185 * @param netif the lwip network interface structure for this slipif 00186 * @param p the pbuf chain packet to send 00187 * @param ipaddr the ip address to send the packet to (not used for slipif) 00188 * @return always returns ERR_OK since the serial layer does not provide return values 00189 */ 00190 static err_t 00191 slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr) 00192 { 00193 LWIP_UNUSED_ARG(ipaddr); 00194 return slipif_output(netif, p); 00195 } 00196 #endif /* LWIP_IPV6 */ 00197 00198 /** 00199 * Handle the incoming SLIP stream character by character 00200 * 00201 * @param netif the lwip network interface structure for this slipif 00202 * @param c received character (multiple calls to this function will 00203 * return a complete packet, NULL is returned before - used for polling) 00204 * @return The IP packet when SLIP_END is received 00205 */ 00206 static struct pbuf* 00207 slipif_rxbyte(struct netif *netif, u8_t c) 00208 { 00209 struct slipif_priv *priv; 00210 struct pbuf *t; 00211 00212 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00213 LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); 00214 00215 priv = (struct slipif_priv *)netif->state; 00216 00217 switch (priv->state) { 00218 case SLIP_RECV_NORMAL: 00219 switch (c) { 00220 case SLIP_END: 00221 if (priv->recved > 0) { 00222 /* Received whole packet. */ 00223 /* Trim the pbuf to the size of the received packet. */ 00224 pbuf_realloc(priv->q, priv->recved); 00225 00226 LINK_STATS_INC(link.recv); 00227 00228 LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved)); 00229 t = priv->q; 00230 priv->p = priv->q = NULL; 00231 priv->i = priv->recved = 0; 00232 return t; 00233 } 00234 return NULL; 00235 case SLIP_ESC: 00236 priv->state = SLIP_RECV_ESCAPE; 00237 return NULL; 00238 default: 00239 break; 00240 } /* end switch (c) */ 00241 break; 00242 case SLIP_RECV_ESCAPE: 00243 /* un-escape END or ESC bytes, leave other bytes 00244 (although that would be a protocol error) */ 00245 switch (c) { 00246 case SLIP_ESC_END: 00247 c = SLIP_END; 00248 break; 00249 case SLIP_ESC_ESC: 00250 c = SLIP_ESC; 00251 break; 00252 default: 00253 break; 00254 } 00255 priv->state = SLIP_RECV_NORMAL; 00256 break; 00257 default: 00258 break; 00259 } /* end switch (priv->state) */ 00260 00261 /* byte received, packet not yet completely received */ 00262 if (priv->p == NULL) { 00263 /* allocate a new pbuf */ 00264 LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); 00265 priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL); 00266 00267 if (priv->p == NULL) { 00268 LINK_STATS_INC(link.drop); 00269 LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); 00270 /* don't process any further since we got no pbuf to receive to */ 00271 return NULL; 00272 } 00273 00274 if (priv->q != NULL) { 00275 /* 'chain' the pbuf to the existing chain */ 00276 pbuf_cat(priv->q, priv->p); 00277 } else { 00278 /* p is the first pbuf in the chain */ 00279 priv->q = priv->p; 00280 } 00281 } 00282 00283 /* this automatically drops bytes if > SLIP_MAX_SIZE */ 00284 if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { 00285 ((u8_t *)priv->p->payload)[priv->i] = c; 00286 priv->recved++; 00287 priv->i++; 00288 if (priv->i >= priv->p->len) { 00289 /* on to the next pbuf */ 00290 priv->i = 0; 00291 if (priv->p->next != NULL && priv->p->next->len > 0) { 00292 /* p is a chain, on to the next in the chain */ 00293 priv->p = priv->p->next; 00294 } else { 00295 /* p is a single pbuf, set it to NULL so next time a new 00296 * pbuf is allocated */ 00297 priv->p = NULL; 00298 } 00299 } 00300 } 00301 return NULL; 00302 } 00303 00304 /** Like slipif_rxbyte, but passes completed packets to netif->input 00305 * 00306 * @param netif The lwip network interface structure for this slipif 00307 * @param data received character 00308 */ 00309 static void 00310 slipif_rxbyte_input(struct netif *netif, u8_t c) 00311 { 00312 struct pbuf *p; 00313 p = slipif_rxbyte(netif, c); 00314 if (p != NULL) { 00315 if (netif->input(p, netif) != ERR_OK) { 00316 pbuf_free(p); 00317 } 00318 } 00319 } 00320 00321 #if SLIP_USE_RX_THREAD 00322 /** 00323 * The SLIP input thread. 00324 * 00325 * Feed the IP layer with incoming packets 00326 * 00327 * @param nf the lwip network interface structure for this slipif 00328 */ 00329 static void 00330 slipif_loop_thread(void *nf) 00331 { 00332 u8_t c; 00333 struct netif *netif = (struct netif *)nf; 00334 struct slipif_priv *priv = (struct slipif_priv *)netif->state; 00335 00336 while (1) { 00337 if (sio_read(priv->sd, &c, 1) > 0) { 00338 slipif_rxbyte_input(netif, c); 00339 } 00340 } 00341 } 00342 #endif /* SLIP_USE_RX_THREAD */ 00343 00344 /** 00345 * SLIP netif initialization 00346 * 00347 * Call the arch specific sio_open and remember 00348 * the opened device in the state field of the netif. 00349 * 00350 * @param netif the lwip network interface structure for this slipif 00351 * @return ERR_OK if serial line could be opened, 00352 * ERR_MEM if no memory could be allocated, 00353 * ERR_IF is serial line couldn't be opened 00354 * 00355 * @note netif->num must contain the number of the serial port to open 00356 * (0 by default). If netif->state is != NULL, it is interpreted as an 00357 * u8_t pointer pointing to the serial port number instead of netif->num. 00358 * 00359 */ 00360 err_t 00361 slipif_init(struct netif *netif) 00362 { 00363 struct slipif_priv *priv; 00364 u8_t sio_num; 00365 00366 LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); 00367 00368 /* Allocate private data */ 00369 priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); 00370 if (!priv) { 00371 return ERR_MEM; 00372 } 00373 00374 netif->name[0] = 's'; 00375 netif->name[1] = 'l'; 00376 #if LWIP_IPV4 00377 netif->output = slipif_output_v4; 00378 #endif /* LWIP_IPV4 */ 00379 #if LWIP_IPV6 00380 netif->output_ip6 = slipif_output_v6; 00381 #endif /* LWIP_IPV6 */ 00382 netif->mtu = SLIP_MAX_SIZE; 00383 00384 /* netif->state or netif->num contain the port number */ 00385 if (netif->state != NULL) { 00386 sio_num = *(u8_t*)netif->state; 00387 } else { 00388 sio_num = netif->num; 00389 } 00390 /* Try to open the serial port. */ 00391 priv->sd = sio_open(sio_num); 00392 if (!priv->sd) { 00393 /* Opening the serial port failed. */ 00394 mem_free(priv); 00395 return ERR_IF; 00396 } 00397 00398 /* Initialize private data */ 00399 priv->p = NULL; 00400 priv->q = NULL; 00401 priv->state = SLIP_RECV_NORMAL; 00402 priv->i = 0; 00403 priv->recved = 0; 00404 #if SLIP_RX_FROM_ISR 00405 priv->rxpackets = NULL; 00406 #endif 00407 00408 netif->state = priv; 00409 00410 /* initialize the snmp variables and counters inside the struct netif */ 00411 MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd)); 00412 00413 #if SLIP_USE_RX_THREAD 00414 /* Create a thread to poll the serial line. */ 00415 sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, 00416 SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); 00417 #endif /* SLIP_USE_RX_THREAD */ 00418 return ERR_OK; 00419 } 00420 00421 /** 00422 * Polls the serial device and feeds the IP layer with incoming packets. 00423 * 00424 * @param netif The lwip network interface structure for this slipif 00425 */ 00426 void 00427 slipif_poll(struct netif *netif) 00428 { 00429 u8_t c; 00430 struct slipif_priv *priv; 00431 00432 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00433 LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); 00434 00435 priv = (struct slipif_priv *)netif->state; 00436 00437 while (sio_tryread(priv->sd, &c, 1) > 0) { 00438 slipif_rxbyte_input(netif, c); 00439 } 00440 } 00441 00442 #if SLIP_RX_FROM_ISR 00443 /** 00444 * Feeds the IP layer with incoming packets that were receive 00445 * 00446 * @param netif The lwip network interface structure for this slipif 00447 */ 00448 void 00449 slipif_process_rxqueue(struct netif *netif) 00450 { 00451 struct slipif_priv *priv; 00452 SYS_ARCH_DECL_PROTECT(old_level); 00453 00454 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00455 LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); 00456 00457 priv = (struct slipif_priv *)netif->state; 00458 00459 SYS_ARCH_PROTECT(old_level); 00460 while (priv->rxpackets != NULL) { 00461 struct pbuf *p = priv->rxpackets; 00462 #if SLIP_RX_QUEUE 00463 /* dequeue packet */ 00464 struct pbuf *q = p; 00465 while ((q->len != q->tot_len) && (q->next != NULL)) { 00466 q = q->next; 00467 } 00468 priv->rxpackets = q->next; 00469 q->next = NULL; 00470 #else /* SLIP_RX_QUEUE */ 00471 priv->rxpackets = NULL; 00472 #endif /* SLIP_RX_QUEUE */ 00473 SYS_ARCH_UNPROTECT(old_level); 00474 if (netif->input(p, netif) != ERR_OK) { 00475 pbuf_free(p); 00476 } 00477 SYS_ARCH_PROTECT(old_level); 00478 } 00479 } 00480 00481 /** Like slipif_rxbyte, but queues completed packets. 00482 * 00483 * @param netif The lwip network interface structure for this slipif 00484 * @param data Received serial byte 00485 */ 00486 static void 00487 slipif_rxbyte_enqueue(struct netif *netif, u8_t data) 00488 { 00489 struct pbuf *p; 00490 struct slipif_priv *priv = (struct slipif_priv *)netif->state; 00491 SYS_ARCH_DECL_PROTECT(old_level); 00492 00493 p = slipif_rxbyte(netif, data); 00494 if (p != NULL) { 00495 SYS_ARCH_PROTECT(old_level); 00496 if (priv->rxpackets != NULL) { 00497 #if SLIP_RX_QUEUE 00498 /* queue multiple pbufs */ 00499 struct pbuf *q = p; 00500 while (q->next != NULL) { 00501 q = q->next; 00502 } 00503 q->next = p; 00504 } else { 00505 #else /* SLIP_RX_QUEUE */ 00506 pbuf_free(priv->rxpackets); 00507 } 00508 { 00509 #endif /* SLIP_RX_QUEUE */ 00510 priv->rxpackets = p; 00511 } 00512 SYS_ARCH_UNPROTECT(old_level); 00513 } 00514 } 00515 00516 /** 00517 * Process a received byte, completed packets are put on a queue that is 00518 * fed into IP through slipif_process_rxqueue(). 00519 * 00520 * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. 00521 * 00522 * @param netif The lwip network interface structure for this slipif 00523 * @param data received character 00524 */ 00525 void 00526 slipif_received_byte(struct netif *netif, u8_t data) 00527 { 00528 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00529 LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); 00530 slipif_rxbyte_enqueue(netif, data); 00531 } 00532 00533 /** 00534 * Process multiple received byte, completed packets are put on a queue that is 00535 * fed into IP through slipif_process_rxqueue(). 00536 * 00537 * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. 00538 * 00539 * @param netif The lwip network interface structure for this slipif 00540 * @param data received character 00541 * @param len Number of received characters 00542 */ 00543 void 00544 slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len) 00545 { 00546 u8_t i; 00547 u8_t *rxdata = data; 00548 LWIP_ASSERT("netif != NULL", (netif != NULL)); 00549 LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); 00550 00551 for (i = 0; i < len; i++, rxdata++) { 00552 slipif_rxbyte_enqueue(netif, *rxdata); 00553 } 00554 } 00555 #endif /* SLIP_RX_FROM_ISR */
Generated on Tue Jul 12 2022 13:15:54 by
1.7.2
