A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

Revision:
60:1d8c7a1e7483
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eth/ar4.cpp	Sat Dec 16 14:39:50 2017 +0000
@@ -0,0 +1,229 @@
+#include    "mbed.h"
+#include     "log.h"
+#include   "clock.h"
+#include     "net.h"
+#include     "mac.h"
+#include "ip4addr.h"
+#include     "arp.h"
+#include    "http.h"
+
+bool Ar4Trace = false;
+
+#define CACHE_TIMEOUT   3600
+#define FREEZE_TIMEOUT  1800
+#define REPLY_TIMEOUT      2
+#define SEND_ATTEMPTS      3
+#define RECORDS_COUNT     20
+
+#define STATE_EMPTY 0
+#define STATE_WANT  1
+#define STATE_SENT  2
+#define STATE_VALID 3
+
+static uint32_t elapsed = 0;
+struct record
+{
+    uint32_t elapsed;
+    uint32_t ip;
+    uint8_t  state;
+    uint8_t  tries;
+    char     mac[6];
+};
+static struct record records[RECORDS_COUNT];
+static int getExistingIp(uint32_t ip)
+{
+    for (int i = 0; i < RECORDS_COUNT; i++)
+    {
+        if (records[i].state && records[i].ip == ip) return i;
+    }
+    return -1;
+}
+static int getOldest()
+{
+    int iN = 0;
+    uint32_t tN = 0xFFFFFFFF;
+    for (int i = 0; i < RECORDS_COUNT; i++)
+    {
+        if (!records[i].state) return i; //Found an empty slot so just return it
+        if (records[i].elapsed < tN)
+        {
+            tN = records[i].elapsed;
+            iN = i;
+        }
+    }  
+    return iN;                         //Otherwise return the oldest
+}
+void Ar4MakeRequestForMacFromIp(uint32_t ip)
+{
+    //Don't treat non ips
+    if (!ip) return;
+    int i;
+    
+    //If a record already exists then request an update
+    i = getExistingIp(ip);
+    if (i > -1)
+    {
+        if (elapsed < records[i].elapsed + FREEZE_TIMEOUT) return;
+        if (Ar4Trace)
+        {
+            LogTimeF("AR4 Updated request for MAC of ");
+            Ip4AddressLog(ip);
+            Log("\r\n");
+        }
+        records[i].state    = STATE_WANT;
+        records[i].tries    = 0;
+        records[i].elapsed  = elapsed;
+        return;
+    }
+    
+    //If a record does not exist then find the first empty slot and add the IP and date
+    if (Ar4Trace)
+    {
+        LogTimeF("AR4 Made request for MAC of ");
+        Ip4AddressLog(ip);
+        Log("\r\n");
+    }
+    i = getOldest();
+    records[i].ip       = ip;
+    records[i].state    = STATE_WANT;
+    records[i].tries    = 0;
+    records[i].elapsed  = elapsed;
+    MacClear(records[i].mac);
+}
+void Ar4AddIpRecord(void (*traceback)(void), char* mac, uint32_t ip)
+{
+    //Don't treat non ips
+    if (!ip)
+    {
+        if (Ar4Trace)
+        {
+            LogTime("Ar4AddIpRecord had blank ip\r\n");
+            if (NetTraceStack) traceback();
+        }
+        return;
+    }
+    if (MacIsEmpty(mac))
+    {
+        if (Ar4Trace)
+        {
+            LogTime("Ar4AddIpRecord had blank mac\r\n");
+            if (NetTraceStack) traceback();
+        }
+        return;
+    }
+    int i;
+    
+    //See if any record corresponds to the IP and, if so, update the MAC and time
+    i = getExistingIp(ip);
+    if (i > -1)
+    {
+        records[i].elapsed   = elapsed;
+        records[i].state = STATE_VALID;
+        MacCopy(records[i].mac, mac);
+        return;
+    }
+    
+    //Otherwise find the first empty slot and add the IP, MAC, and date
+    i = getOldest();
+    records[i].ip       = ip;
+    records[i].elapsed  = elapsed;
+    records[i].state = STATE_VALID;
+    MacCopy(records[i].mac, mac);
+    return;
+}
+void Ar4IpToMac(uint32_t ip, char* mac)
+{
+    for (int i = 0; i < RECORDS_COUNT; i++)
+    {
+        if (records[i].state == STATE_VALID && records[i].ip == ip)
+        {
+            MacCopy(mac, records[i].mac);
+            return;
+        }
+    }
+    MacClear(mac);
+}
+void Ar4SendHttp()
+{
+    for (int i = 0; i < RECORDS_COUNT; i++)
+    {
+        if (records[i].state)
+        {
+            HttpAddF("%4u ", (elapsed - records[i].elapsed) / 60);
+            
+            int ipLen = Ip4AddressHttp(records[i].ip);
+            HttpFillChar(' ', 40 - ipLen);
+            
+            MacHttp(records[i].mac);
+            
+            HttpAddChar('\r');
+            HttpAddChar('\n');
+        }
+    }
+}
+static void clear(struct record* pr)
+{
+    pr->state = STATE_EMPTY;
+}
+static void clearCache(struct record* pr)
+{
+    if (elapsed > pr->elapsed + CACHE_TIMEOUT) clear(pr);
+}
+static void retry(struct record* pr)
+{
+    if (pr->state == STATE_SENT && elapsed > pr->elapsed + REPLY_TIMEOUT)
+    {
+        if (pr->tries < SEND_ATTEMPTS)
+        {
+            pr->state   = STATE_WANT;
+            pr->elapsed = elapsed;
+            pr->tries++;
+        }
+        else
+        {
+            clear(pr);
+        }
+    }
+}
+static void sendRequest(struct record* pr)
+{
+    if (!ArpResolveRequestFlag)
+    {
+        if (pr->state == STATE_WANT)
+        {
+            if (Ar4Trace)
+            {
+                LogTimeF("AR4 Send request for MAC from IP4 ");
+                Ip4AddressLog(pr->ip);
+                Log("\r\n");
+            }
+            ArpAddressToResolve = pr->ip;
+            ArpResolveRequestFlag = true;
+            pr->state   = STATE_SENT;
+            pr->elapsed = elapsed;
+            return;
+        }
+    }
+}
+void Ar4Main()
+{
+    static int i = -1;
+    i++;
+    if (i >= RECORDS_COUNT) i = 0;
+    
+    struct record* pr = &records[i];
+    
+    clearCache (pr);
+    retry      (pr);
+    sendRequest(pr);
+    
+    if (ClockTicked) elapsed++;
+}
+void Ar4Init()
+{
+    for (int i = 0; i < RECORDS_COUNT; i++)
+    {
+        struct record* pr = &records[i];
+        clear(pr);
+    }
+}