Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Committer:
iva2k
Date:
Mon Jun 14 03:24:33 2010 +0000
Revision:
1:3ee499525aa5
Parent:
0:e614f7875b60

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
iva2k 0:e614f7875b60 1 /**
iva2k 0:e614f7875b60 2 * @file
iva2k 0:e614f7875b60 3 * Ethernet Interface Skeleton
iva2k 0:e614f7875b60 4 *
iva2k 0:e614f7875b60 5 */
iva2k 0:e614f7875b60 6
iva2k 0:e614f7875b60 7 /*
iva2k 0:e614f7875b60 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
iva2k 0:e614f7875b60 9 * All rights reserved.
iva2k 0:e614f7875b60 10 *
iva2k 0:e614f7875b60 11 * Redistribution and use in source and binary forms, with or without modification,
iva2k 0:e614f7875b60 12 * are permitted provided that the following conditions are met:
iva2k 0:e614f7875b60 13 *
iva2k 0:e614f7875b60 14 * 1. Redistributions of source code must retain the above copyright notice,
iva2k 0:e614f7875b60 15 * this list of conditions and the following disclaimer.
iva2k 0:e614f7875b60 16 * 2. Redistributions in binary form must reproduce the above copyright notice,
iva2k 0:e614f7875b60 17 * this list of conditions and the following disclaimer in the documentation
iva2k 0:e614f7875b60 18 * and/or other materials provided with the distribution.
iva2k 0:e614f7875b60 19 * 3. The name of the author may not be used to endorse or promote products
iva2k 0:e614f7875b60 20 * derived from this software without specific prior written permission.
iva2k 0:e614f7875b60 21 *
iva2k 0:e614f7875b60 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
iva2k 0:e614f7875b60 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
iva2k 0:e614f7875b60 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
iva2k 0:e614f7875b60 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
iva2k 0:e614f7875b60 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
iva2k 0:e614f7875b60 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
iva2k 0:e614f7875b60 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
iva2k 0:e614f7875b60 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
iva2k 0:e614f7875b60 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
iva2k 0:e614f7875b60 31 * OF SUCH DAMAGE.
iva2k 0:e614f7875b60 32 *
iva2k 0:e614f7875b60 33 * This file is part of the lwIP TCP/IP stack.
iva2k 0:e614f7875b60 34 *
iva2k 0:e614f7875b60 35 * Author: Adam Dunkels <adam@sics.se>
iva2k 0:e614f7875b60 36 *
iva2k 0:e614f7875b60 37 */
iva2k 0:e614f7875b60 38
iva2k 0:e614f7875b60 39 /*
iva2k 0:e614f7875b60 40 * This file is a skeleton for developing Ethernet network interface
iva2k 0:e614f7875b60 41 * drivers for lwIP. Add code to the low_level functions and do a
iva2k 0:e614f7875b60 42 * search-and-replace for the word "ethernetif" to replace it with
iva2k 0:e614f7875b60 43 * something that better describes your network interface.
iva2k 0:e614f7875b60 44 */
iva2k 0:e614f7875b60 45
iva2k 0:e614f7875b60 46 #include "lwip/opt.h"
iva2k 0:e614f7875b60 47
iva2k 0:e614f7875b60 48 #if 0 /* don't build, this is only a skeleton, see previous comment */
iva2k 0:e614f7875b60 49
iva2k 0:e614f7875b60 50 #include "lwip/def.h"
iva2k 0:e614f7875b60 51 #include "lwip/mem.h"
iva2k 0:e614f7875b60 52 #include "lwip/pbuf.h"
iva2k 0:e614f7875b60 53 #include "lwip/sys.h"
iva2k 0:e614f7875b60 54 #include <lwip/stats.h>
iva2k 0:e614f7875b60 55 #include <lwip/snmp.h>
iva2k 0:e614f7875b60 56 #include "netif/etharp.h"
iva2k 0:e614f7875b60 57 #include "netif/ppp_oe.h"
iva2k 0:e614f7875b60 58
iva2k 0:e614f7875b60 59 /* Define those to better describe your network interface. */
iva2k 0:e614f7875b60 60 #define IFNAME0 'e'
iva2k 0:e614f7875b60 61 #define IFNAME1 'n'
iva2k 0:e614f7875b60 62
iva2k 0:e614f7875b60 63 /**
iva2k 0:e614f7875b60 64 * Helper struct to hold private data used to operate your ethernet interface.
iva2k 0:e614f7875b60 65 * Keeping the ethernet address of the MAC in this struct is not necessary
iva2k 0:e614f7875b60 66 * as it is already kept in the struct netif.
iva2k 0:e614f7875b60 67 * But this is only an example, anyway...
iva2k 0:e614f7875b60 68 */
iva2k 0:e614f7875b60 69 struct ethernetif {
iva2k 0:e614f7875b60 70 struct eth_addr *ethaddr;
iva2k 0:e614f7875b60 71 /* Add whatever per-interface state that is needed here. */
iva2k 0:e614f7875b60 72 };
iva2k 0:e614f7875b60 73
iva2k 0:e614f7875b60 74 /* Forward declarations. */
iva2k 0:e614f7875b60 75 static void ethernetif_input(struct netif *netif);
iva2k 0:e614f7875b60 76
iva2k 0:e614f7875b60 77 /**
iva2k 0:e614f7875b60 78 * In this function, the hardware should be initialized.
iva2k 0:e614f7875b60 79 * Called from ethernetif_init().
iva2k 0:e614f7875b60 80 *
iva2k 0:e614f7875b60 81 * @param netif the already initialized lwip network interface structure
iva2k 0:e614f7875b60 82 * for this ethernetif
iva2k 0:e614f7875b60 83 */
iva2k 0:e614f7875b60 84 static void
iva2k 0:e614f7875b60 85 low_level_init(struct netif *netif)
iva2k 0:e614f7875b60 86 {
iva2k 0:e614f7875b60 87 struct ethernetif *ethernetif = netif->state;
iva2k 0:e614f7875b60 88
iva2k 0:e614f7875b60 89 /* set MAC hardware address length */
iva2k 0:e614f7875b60 90 netif->hwaddr_len = ETHARP_HWADDR_LEN;
iva2k 0:e614f7875b60 91
iva2k 0:e614f7875b60 92 /* set MAC hardware address */
iva2k 0:e614f7875b60 93 netif->hwaddr[0] = ;
iva2k 0:e614f7875b60 94 ...
iva2k 0:e614f7875b60 95 netif->hwaddr[5] = ;
iva2k 0:e614f7875b60 96
iva2k 0:e614f7875b60 97 /* maximum transfer unit */
iva2k 0:e614f7875b60 98 netif->mtu = 1500;
iva2k 0:e614f7875b60 99
iva2k 0:e614f7875b60 100 /* device capabilities */
iva2k 0:e614f7875b60 101 /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
iva2k 0:e614f7875b60 102 netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
iva2k 0:e614f7875b60 103
iva2k 0:e614f7875b60 104 /* Do whatever else is needed to initialize interface. */
iva2k 0:e614f7875b60 105 }
iva2k 0:e614f7875b60 106
iva2k 0:e614f7875b60 107 /**
iva2k 0:e614f7875b60 108 * This function should do the actual transmission of the packet. The packet is
iva2k 0:e614f7875b60 109 * contained in the pbuf that is passed to the function. This pbuf
iva2k 0:e614f7875b60 110 * might be chained.
iva2k 0:e614f7875b60 111 *
iva2k 0:e614f7875b60 112 * @param netif the lwip network interface structure for this ethernetif
iva2k 0:e614f7875b60 113 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
iva2k 0:e614f7875b60 114 * @return ERR_OK if the packet could be sent
iva2k 0:e614f7875b60 115 * an err_t value if the packet couldn't be sent
iva2k 0:e614f7875b60 116 *
iva2k 0:e614f7875b60 117 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
iva2k 0:e614f7875b60 118 * strange results. You might consider waiting for space in the DMA queue
iva2k 0:e614f7875b60 119 * to become availale since the stack doesn't retry to send a packet
iva2k 0:e614f7875b60 120 * dropped because of memory failure (except for the TCP timers).
iva2k 0:e614f7875b60 121 */
iva2k 0:e614f7875b60 122
iva2k 0:e614f7875b60 123 static err_t
iva2k 0:e614f7875b60 124 low_level_output(struct netif *netif, struct pbuf *p)
iva2k 0:e614f7875b60 125 {
iva2k 0:e614f7875b60 126 struct ethernetif *ethernetif = netif->state;
iva2k 0:e614f7875b60 127 struct pbuf *q;
iva2k 0:e614f7875b60 128
iva2k 0:e614f7875b60 129 initiate transfer();
iva2k 0:e614f7875b60 130
iva2k 0:e614f7875b60 131 #if ETH_PAD_SIZE
iva2k 0:e614f7875b60 132 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
iva2k 0:e614f7875b60 133 #endif
iva2k 0:e614f7875b60 134
iva2k 0:e614f7875b60 135 for(q = p; q != NULL; q = q->next) {
iva2k 0:e614f7875b60 136 /* Send the data from the pbuf to the interface, one pbuf at a
iva2k 0:e614f7875b60 137 time. The size of the data in each pbuf is kept in the ->len
iva2k 0:e614f7875b60 138 variable. */
iva2k 0:e614f7875b60 139 send data from(q->payload, q->len);
iva2k 0:e614f7875b60 140 }
iva2k 0:e614f7875b60 141
iva2k 0:e614f7875b60 142 signal that packet should be sent();
iva2k 0:e614f7875b60 143
iva2k 0:e614f7875b60 144 #if ETH_PAD_SIZE
iva2k 0:e614f7875b60 145 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
iva2k 0:e614f7875b60 146 #endif
iva2k 0:e614f7875b60 147
iva2k 0:e614f7875b60 148 LINK_STATS_INC(link.xmit);
iva2k 0:e614f7875b60 149
iva2k 0:e614f7875b60 150 return ERR_OK;
iva2k 0:e614f7875b60 151 }
iva2k 0:e614f7875b60 152
iva2k 0:e614f7875b60 153 /**
iva2k 0:e614f7875b60 154 * Should allocate a pbuf and transfer the bytes of the incoming
iva2k 0:e614f7875b60 155 * packet from the interface into the pbuf.
iva2k 0:e614f7875b60 156 *
iva2k 0:e614f7875b60 157 * @param netif the lwip network interface structure for this ethernetif
iva2k 0:e614f7875b60 158 * @return a pbuf filled with the received packet (including MAC header)
iva2k 0:e614f7875b60 159 * NULL on memory error
iva2k 0:e614f7875b60 160 */
iva2k 0:e614f7875b60 161 static struct pbuf *
iva2k 0:e614f7875b60 162 low_level_input(struct netif *netif)
iva2k 0:e614f7875b60 163 {
iva2k 0:e614f7875b60 164 struct ethernetif *ethernetif = netif->state;
iva2k 0:e614f7875b60 165 struct pbuf *p, *q;
iva2k 0:e614f7875b60 166 u16_t len;
iva2k 0:e614f7875b60 167
iva2k 0:e614f7875b60 168 /* Obtain the size of the packet and put it into the "len"
iva2k 0:e614f7875b60 169 variable. */
iva2k 0:e614f7875b60 170 len = ;
iva2k 0:e614f7875b60 171
iva2k 0:e614f7875b60 172 #if ETH_PAD_SIZE
iva2k 0:e614f7875b60 173 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
iva2k 0:e614f7875b60 174 #endif
iva2k 0:e614f7875b60 175
iva2k 0:e614f7875b60 176 /* We allocate a pbuf chain of pbufs from the pool. */
iva2k 0:e614f7875b60 177 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
iva2k 0:e614f7875b60 178
iva2k 0:e614f7875b60 179 if (p != NULL) {
iva2k 0:e614f7875b60 180
iva2k 0:e614f7875b60 181 #if ETH_PAD_SIZE
iva2k 0:e614f7875b60 182 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
iva2k 0:e614f7875b60 183 #endif
iva2k 0:e614f7875b60 184
iva2k 0:e614f7875b60 185 /* We iterate over the pbuf chain until we have read the entire
iva2k 0:e614f7875b60 186 * packet into the pbuf. */
iva2k 0:e614f7875b60 187 for(q = p; q != NULL; q = q->next) {
iva2k 0:e614f7875b60 188 /* Read enough bytes to fill this pbuf in the chain. The
iva2k 0:e614f7875b60 189 * available data in the pbuf is given by the q->len
iva2k 0:e614f7875b60 190 * variable.
iva2k 0:e614f7875b60 191 * This does not necessarily have to be a memcpy, you can also preallocate
iva2k 0:e614f7875b60 192 * pbufs for a DMA-enabled MAC and after receiving truncate it to the
iva2k 0:e614f7875b60 193 * actually received size. In this case, ensure the tot_len member of the
iva2k 0:e614f7875b60 194 * pbuf is the sum of the chained pbuf len members.
iva2k 0:e614f7875b60 195 */
iva2k 0:e614f7875b60 196 read data into(q->payload, q->len);
iva2k 0:e614f7875b60 197 }
iva2k 0:e614f7875b60 198 acknowledge that packet has been read();
iva2k 0:e614f7875b60 199
iva2k 0:e614f7875b60 200 #if ETH_PAD_SIZE
iva2k 0:e614f7875b60 201 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
iva2k 0:e614f7875b60 202 #endif
iva2k 0:e614f7875b60 203
iva2k 0:e614f7875b60 204 LINK_STATS_INC(link.recv);
iva2k 0:e614f7875b60 205 } else {
iva2k 0:e614f7875b60 206 drop packet();
iva2k 0:e614f7875b60 207 LINK_STATS_INC(link.memerr);
iva2k 0:e614f7875b60 208 LINK_STATS_INC(link.drop);
iva2k 0:e614f7875b60 209 }
iva2k 0:e614f7875b60 210
iva2k 0:e614f7875b60 211 return p;
iva2k 0:e614f7875b60 212 }
iva2k 0:e614f7875b60 213
iva2k 0:e614f7875b60 214 /**
iva2k 0:e614f7875b60 215 * This function should be called when a packet is ready to be read
iva2k 0:e614f7875b60 216 * from the interface. It uses the function low_level_input() that
iva2k 0:e614f7875b60 217 * should handle the actual reception of bytes from the network
iva2k 0:e614f7875b60 218 * interface. Then the type of the received packet is determined and
iva2k 0:e614f7875b60 219 * the appropriate input function is called.
iva2k 0:e614f7875b60 220 *
iva2k 0:e614f7875b60 221 * @param netif the lwip network interface structure for this ethernetif
iva2k 0:e614f7875b60 222 */
iva2k 0:e614f7875b60 223 static void
iva2k 0:e614f7875b60 224 ethernetif_input(struct netif *netif)
iva2k 0:e614f7875b60 225 {
iva2k 0:e614f7875b60 226 struct ethernetif *ethernetif;
iva2k 0:e614f7875b60 227 struct eth_hdr *ethhdr;
iva2k 0:e614f7875b60 228 struct pbuf *p;
iva2k 0:e614f7875b60 229
iva2k 0:e614f7875b60 230 ethernetif = netif->state;
iva2k 0:e614f7875b60 231
iva2k 0:e614f7875b60 232 /* move received packet into a new pbuf */
iva2k 0:e614f7875b60 233 p = low_level_input(netif);
iva2k 0:e614f7875b60 234 /* no packet could be read, silently ignore this */
iva2k 0:e614f7875b60 235 if (p == NULL) return;
iva2k 0:e614f7875b60 236 /* points to packet payload, which starts with an Ethernet header */
iva2k 0:e614f7875b60 237 ethhdr = p->payload;
iva2k 0:e614f7875b60 238
iva2k 0:e614f7875b60 239 switch (htons(ethhdr->type)) {
iva2k 0:e614f7875b60 240 /* IP or ARP packet? */
iva2k 0:e614f7875b60 241 case ETHTYPE_IP:
iva2k 0:e614f7875b60 242 case ETHTYPE_ARP:
iva2k 0:e614f7875b60 243 #if PPPOE_SUPPORT
iva2k 0:e614f7875b60 244 /* PPPoE packet? */
iva2k 0:e614f7875b60 245 case ETHTYPE_PPPOEDISC:
iva2k 0:e614f7875b60 246 case ETHTYPE_PPPOE:
iva2k 0:e614f7875b60 247 #endif /* PPPOE_SUPPORT */
iva2k 0:e614f7875b60 248 /* full packet send to tcpip_thread to process */
iva2k 0:e614f7875b60 249 if (netif->input(p, netif)!=ERR_OK)
iva2k 0:e614f7875b60 250 { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
iva2k 0:e614f7875b60 251 pbuf_free(p);
iva2k 0:e614f7875b60 252 p = NULL;
iva2k 0:e614f7875b60 253 }
iva2k 0:e614f7875b60 254 break;
iva2k 0:e614f7875b60 255
iva2k 0:e614f7875b60 256 default:
iva2k 0:e614f7875b60 257 pbuf_free(p);
iva2k 0:e614f7875b60 258 p = NULL;
iva2k 0:e614f7875b60 259 break;
iva2k 0:e614f7875b60 260 }
iva2k 0:e614f7875b60 261 }
iva2k 0:e614f7875b60 262
iva2k 0:e614f7875b60 263 /**
iva2k 0:e614f7875b60 264 * Should be called at the beginning of the program to set up the
iva2k 0:e614f7875b60 265 * network interface. It calls the function low_level_init() to do the
iva2k 0:e614f7875b60 266 * actual setup of the hardware.
iva2k 0:e614f7875b60 267 *
iva2k 0:e614f7875b60 268 * This function should be passed as a parameter to netif_add().
iva2k 0:e614f7875b60 269 *
iva2k 0:e614f7875b60 270 * @param netif the lwip network interface structure for this ethernetif
iva2k 0:e614f7875b60 271 * @return ERR_OK if the loopif is initialized
iva2k 0:e614f7875b60 272 * ERR_MEM if private data couldn't be allocated
iva2k 0:e614f7875b60 273 * any other err_t on error
iva2k 0:e614f7875b60 274 */
iva2k 0:e614f7875b60 275 err_t
iva2k 0:e614f7875b60 276 ethernetif_init(struct netif *netif)
iva2k 0:e614f7875b60 277 {
iva2k 0:e614f7875b60 278 struct ethernetif *ethernetif;
iva2k 0:e614f7875b60 279
iva2k 0:e614f7875b60 280 LWIP_ASSERT("netif != NULL", (netif != NULL));
iva2k 0:e614f7875b60 281
iva2k 0:e614f7875b60 282 ethernetif = mem_malloc(sizeof(struct ethernetif));
iva2k 0:e614f7875b60 283 if (ethernetif == NULL) {
iva2k 0:e614f7875b60 284 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
iva2k 0:e614f7875b60 285 return ERR_MEM;
iva2k 0:e614f7875b60 286 }
iva2k 0:e614f7875b60 287
iva2k 0:e614f7875b60 288 #if LWIP_NETIF_HOSTNAME
iva2k 0:e614f7875b60 289 /* Initialize interface hostname */
iva2k 0:e614f7875b60 290 netif->hostname = "lwip";
iva2k 0:e614f7875b60 291 #endif /* LWIP_NETIF_HOSTNAME */
iva2k 0:e614f7875b60 292
iva2k 0:e614f7875b60 293 /*
iva2k 0:e614f7875b60 294 * Initialize the snmp variables and counters inside the struct netif.
iva2k 0:e614f7875b60 295 * The last argument should be replaced with your link speed, in units
iva2k 0:e614f7875b60 296 * of bits per second.
iva2k 0:e614f7875b60 297 */
iva2k 0:e614f7875b60 298 NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
iva2k 0:e614f7875b60 299
iva2k 0:e614f7875b60 300 netif->state = ethernetif;
iva2k 0:e614f7875b60 301 netif->name[0] = IFNAME0;
iva2k 0:e614f7875b60 302 netif->name[1] = IFNAME1;
iva2k 0:e614f7875b60 303 /* We directly use etharp_output() here to save a function call.
iva2k 0:e614f7875b60 304 * You can instead declare your own function an call etharp_output()
iva2k 0:e614f7875b60 305 * from it if you have to do some checks before sending (e.g. if link
iva2k 0:e614f7875b60 306 * is available...) */
iva2k 0:e614f7875b60 307 netif->output = etharp_output;
iva2k 0:e614f7875b60 308 netif->linkoutput = low_level_output;
iva2k 0:e614f7875b60 309
iva2k 0:e614f7875b60 310 ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
iva2k 0:e614f7875b60 311
iva2k 0:e614f7875b60 312 /* initialize the hardware */
iva2k 0:e614f7875b60 313 low_level_init(netif);
iva2k 0:e614f7875b60 314
iva2k 0:e614f7875b60 315 return ERR_OK;
iva2k 0:e614f7875b60 316 }
iva2k 0:e614f7875b60 317
iva2k 0:e614f7875b60 318 #endif /* 0 */