Implementation of the NetworkSocketAPI for LWIP

Dependencies:   lwip-eth lwip-sys lwip

Dependents:   HelloLWIPInterface HelloLWIPInterfaceNonBlocking LWIPInterfaceTests SimpleHTTPExample ... more

Revision:
2:7fb7e78cb17f
Parent:
1:2fbcfc9c12dd
Child:
3:774869068511
--- a/LWIPInterface.cpp	Fri Feb 26 17:40:23 2016 +0000
+++ b/LWIPInterface.cpp	Thu Feb 25 11:09:49 2016 -0600
@@ -14,4 +14,235 @@
  * limitations under the License.
  */
  
- #include "LWIPInterface.h"
\ No newline at end of file
+#include "LWIPInterface.h"
+
+#include "mbed.h"
+#include "lwip/inet.h"
+#include "lwip/netif.h"
+#include "lwip/dhcp.h"
+#include "lwip/tcpip.h"
+#include "lwip/sockets.h"
+#include "lwip/netdb.h"
+#include "netif/etharp.h"
+#include "eth_arch.h"
+
+
+#define LWIP_TIMEOUT 15000
+
+
+/* TCP/IP and Network Interface Initialisation */
+static LWIPInterface *iface = 0;
+static struct netif netif;
+
+static char mac_addr[NS_MAC_SIZE] = "\0";
+
+static Semaphore tcpip_inited(0);
+static Semaphore netif_linked(0);
+static Semaphore netif_up(0);
+
+static void tcpip_init_done(void *) {
+    tcpip_inited.release();
+}
+
+static void netif_link_callback(struct netif *netif) {
+    if (netif_is_link_up(netif)) {
+        netif_linked.release();
+    }
+}
+
+static void netif_status_callback(struct netif *netif) {
+    if (netif_is_up(netif)) {
+        iface->setIPAddress  (inet_ntoa(netif->ip_addr));
+        iface->setNetworkMask(inet_ntoa(netif->netmask));
+        iface->setGateway    (inet_ntoa(netif->gw));
+        netif_up.release();
+    }
+}
+
+static void init_netif(ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) {
+    tcpip_init(tcpip_init_done, NULL);
+    tcpip_inited.wait();
+    
+    memset((void*) &netif, 0, sizeof(netif));
+    netif_add(&netif, ipaddr, netmask, gw, NULL, eth_arch_enetif_init, tcpip_input);
+    netif_set_default(&netif);
+    
+    netif_set_link_callback  (&netif, netif_link_callback);
+    netif_set_status_callback(&netif, netif_status_callback);
+}
+
+static void set_mac_address(void) {
+#if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE)
+    snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", MBED_MAC_ADDR_0, MBED_MAC_ADDR_1, MBED_MAC_ADDR_2,
+             MBED_MAC_ADDR_3, MBED_MAC_ADDR_4, MBED_MAC_ADDR_5);
+#else
+    char mac[6];
+    mbed_mac_address(mac);
+    snprintf(mac_addr, 19, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+#endif
+}
+
+
+// LWIPInterface implementation
+int32_t LWIPInterface::connect()
+{
+    // Only one instance of LWIP is currently supported
+    if (iface) {
+        return NS_ERROR_DEVICE_ERROR;
+    }
+
+    iface = this;
+
+    // Set up network
+    set_mac_address();
+
+    if (getDHCP()) {
+        init_netif(0, 0, 0);
+    } else {
+        ip_addr_t ip_n, mask_n, gateway_n;
+        inet_aton(getIPAddress(), &ip_n);
+        inet_aton(getNetworkMask(), &mask_n);
+        inet_aton(getGateway(), &gateway_n);
+        init_netif(&ip_n, &mask_n, &gateway_n);
+    }
+
+    // Connect to network
+    eth_arch_enable_interrupts();
+
+    if (getDHCP()) {
+        dhcp_start(&netif);
+        
+        // Wait for an IP Address
+        // -1: error, 0: timeout
+        if (netif_up.wait(LWIP_TIMEOUT) < 0) {
+            return NS_ERROR_TIMEOUT;
+        }
+    } else {
+        netif_set_up(&netif);
+        
+        // Wait for the link up
+        if (netif_linked.wait(LWIP_TIMEOUT) < 0) {
+            return NS_ERROR_TIMEOUT;
+        }
+    }
+
+    return 0;
+}
+
+int32_t LWIPInterface::disconnect()
+{
+    if (getDHCP()) {
+        dhcp_release(&netif);
+        dhcp_stop(&netif);
+    } else {
+        netif_set_down(&netif);
+    }
+    
+    eth_arch_disable_interrupts();
+    
+    return 0;
+}
+
+const char *LWIPInterface::getMACAddress() 
+{
+    return mac_addr;
+}
+
+
+/** LWIPSocket class
+ *  Implementation of the TCP SocketInterface for LWIP
+ */
+class LWIPSocket : public SocketInterface
+{
+public:
+    LWIPSocket(int fd) : fd(fd) {}
+
+    // Implementation of SocketInterface
+    virtual int32_t open(const char *ip, uint16_t port);
+    virtual int32_t close();
+
+    virtual int32_t send(const void *data, uint32_t size);
+    virtual int32_t recv(void *data, uint32_t size);
+
+    int fd;
+};
+
+
+SocketInterface *LWIPInterface::createSocket(socket_protocol_t proto)
+{
+    int type = (proto == SOCK_UDP) ? SOCK_DGRAM : SOCK_STREAM;
+    int fd = lwip_socket(AF_INET, type, 0);
+
+    if (fd < 0) {
+        return 0;
+    }
+
+    return new LWIPSocket(fd);
+}
+
+void LWIPInterface::destroySocket(SocketInterface *siface)
+{
+    LWIPSocket *socket = (LWIPSocket *)siface;
+    lwip_close(socket->fd);
+
+    delete socket;
+}
+
+
+// TCP SocketInterface implementation
+int32_t LWIPSocket::open(const char *ip, uint16_t port)
+{
+    struct sockaddr_in host;
+    memset(&host, 0, sizeof host);
+    inet_aton(ip, &host.sin_addr);
+    host.sin_family = AF_INET;
+    host.sin_port = htons(port);
+
+    if (lwip_connect(fd, (const struct sockaddr *)&host, sizeof host) < 0) {
+        return NS_ERROR_NO_CONNECTION;
+    }
+
+    return 0;
+}
+
+int32_t LWIPSocket::close()
+{
+    return 0;
+}
+
+int32_t LWIPSocket::send(const void *voiddata, uint32_t size)
+{
+    uint8_t *data = (uint8_t *)voiddata;
+    uint32_t writtenLen = 0;
+
+    while (writtenLen < size) {
+        int ret = lwip_send(fd, data + writtenLen, size - writtenLen, 0);
+
+        if (ret > 0) {
+            writtenLen += ret;
+        } else if (ret == 0) {
+            return NS_ERROR_NO_CONNECTION;
+        } else {
+            return NS_ERROR_DEVICE_ERROR;
+        }
+    }
+
+    return 0;
+}
+
+int32_t LWIPSocket::recv(void *data, uint32_t size)
+{
+    int ret = lwip_recv(fd, data, size, MSG_DONTWAIT);
+
+    if (ret > 0) {
+        return ret;
+    } else if (ret == 0) {
+        return NS_ERROR_NO_CONNECTION;
+    } else if (ret == -1) {
+        return 0;
+    } else {
+        return NS_ERROR_DEVICE_ERROR;
+    }
+}
+
+