program to test the TCP socket connection of EthernetInterface. specifically, to reproduce a problem that results in the mbed re-sending the wrong packet after a packet loss

Dependencies:   EthernetInterface FatFileSystemCpp SDFileSystem mbed-rtos mbed

Revision:
0:53afc51b78a9
Child:
1:6b90cbfe0c9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Sep 22 04:01:27 2012 +0000
@@ -0,0 +1,303 @@
+#include "mbed.h"
+
+#include "SDFileSystem.h"
+#include "TCPSocketConnection.h"
+#include "EthernetInterface.h"
+#include "string"
+#include "fakeData.h"
+
+//#define DEBUG                 // turn on debug output if defined (note this slows down processing due to serial baud rate!)
+//#define PRINT_DOIO_RESULT     // print the number of bytes DoIO returns
+
+// if this is defined, read files starting with "S" from the SD card
+// otherwise use the fake data in fakeData.h (from memory)
+//#define USE_DATA_FROM_SD
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+static const char*          kRserv      = "128.195.204.151";
+static const unsigned short kRport      = 6666;
+
+static const char*          kMyIp       = "128.195.204.148";
+static const char*          kMyMask     = "255.255.255.0";
+static const char*          kMyGate     = "128.195.204.1";
+
+static const unsigned int   kBSTime     = 946684800u; // 1/1/2000 00:00:00 UTC
+static const int            kSecsPerDay = 3600*24;
+static const int            kBuffSize   = 1024;
+// all chunks must be smaller than kBuffSize
+static const int            kNCsizes    = 5;
+static const int            gChunkSize[kNCsizes] = { 9, 26, 711, 40, 432 };
+static const int            kTotFakeDat = 2097152; // if sending fake data, send 2 MB total
+static const int            kTimeout    = 300; // seconds
+
+static const char*          kSDsubDir   = "/sd";
+static const char*          kFileTag    = "S"; // send files starting with this tag
+
+static char                 gBuff[kBuffSize];
+static SDFileSystem         sd(p5, p6, p7, p8, kSDsubDir+1);
+static LocalFileSystem      local("local");
+static EthernetInterface*   gEth(0);
+static TCPSocketConnection* gSock(0);
+static Serial               gCpu( USBTX, USBRX );
+
+// function pointer to send, receive, etc
+typedef int (TCPSocketConnection::*TCPSendRecv)(char*, int);
+#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
+
+// forward declarations
+bool Connect(const int timeout);
+void SendData(FILE* inf, const int timeout);
+FILE* OpenSDFile(const char* name, const char* mode);
+void SendAllFakeData(const int totalBytes, const int timeout);
+void SendAllFiles(const int timeout);
+bool IsTimedOut(const int timeout_clock);
+void dispStrBytes(const char* const s, const int len);
+int DoIO(char* const data,
+         const int length,
+         const int timeout_clock,
+         TCPSendRecv fcn);
+int ReceiveAll(char* const buf, const int mlen, const int timeout_clock);
+int SendAll(char* const data, const int length, const int timeout_clock);
+
+
+int main() {
+    led1=1;
+    set_time(kBSTime);
+    if (Connect(time(0)+kTimeout)) {
+        led2=1;
+#ifdef USE_DATA_FROM_SD
+        SendAllFiles(time(0)+kTimeout);
+#else
+        SendAllFakeData(kTotFakeDat, time(0)+kTimeout);
+#endif
+    } else {
+        led4=1;
+    }
+    if (gSock!=0) {
+        gSock->close();
+    }
+    if (gEth!=0) {
+        gEth->disconnect();
+    }
+    while (true) {
+        led1=0; wait(0.5); led1=1; wait(0.5);
+    }
+}
+
+bool Connect(const int timeout) {
+
+#ifdef DEBUG
+    printf("Connect\r\n");
+#endif
+    
+    gEth = new EthernetInterface;
+    gSock = new TCPSocketConnection;
+
+    gEth->init(kMyIp, kMyMask, kMyGate);
+
+    bool isConn = false;
+
+    while ( (isConn==false) && (IsTimedOut(timeout)==false) ) {
+        wait_ms(250);
+        isConn = (gEth->connect()==0);
+    }
+#ifdef DEBUG
+    printf("eth isConn=%d\r\n",(int)isConn);
+#endif
+    
+    isConn=false;
+    while ( (isConn==false) && (IsTimedOut(timeout)==false) ) {
+        wait_ms(250);
+        isConn = (gSock->connect(kRserv, kRport)==0);
+    }
+#ifdef DEBUG
+    printf("sock isConn=%d\r\n",(int)isConn);
+#endif
+    return isConn;
+}
+
+void SendAllFakeData(const int totalBytes, const int timeout) {
+    // send the fake data in chunks
+
+    const int* const csend = gChunkSize + kNCsizes;
+    const int* cs = gChunkSize;
+    
+    int br=0;  // bytes read/sent so far
+    int tcs=0; // this chunk size
+    while ( br<totalBytes ) {
+        
+        // read a chunk
+        tcs = (*cs < kFakeDataSize) ? (*cs) : kFakeDataSize;
+        memcpy(gBuff, gFakeData, tcs);
+        
+        // send this chunk
+        br += SendAll(gBuff, tcs, timeout);
+        
+        // change chunk size
+        ++cs;
+        if (cs==csend) {
+            cs = gChunkSize;
+        }
+    }
+}
+
+void SendData(FILE* inf, const int timeout) {
+    // send the SD card data in chunks
+    
+    // store position in file so we can go back to it afterwards
+    const int fpos = ftell(inf);
+    if (fpos>0) {
+        fseek(inf, 0, SEEK_SET);
+    }
+    // how many bytes?
+    fseek(inf, 0, SEEK_END); // go to end
+    const int fend = ftell(inf);
+    fseek(inf, 0, SEEK_SET); // go to start
+#ifdef DEBUG
+    printf("fend=%d\r\n",fend);
+    printf("fpos=%d\r\n",fpos);
+#endif
+    
+    const int* const csend = gChunkSize + kNCsizes;
+    const int* cs = gChunkSize;
+    
+    int br=0;  // bytes read/sent so far
+    int tcs=0; // this chunk size
+    while ( br<fend ) {
+        
+        // read a chunk or the remainder of the file
+        tcs = ((br+(*cs))<fend) ? (*cs) : (fend-br);
+        fread(gBuff, tcs, 1, inf);
+        
+        // send this chunk
+        br += SendAll(gBuff, tcs, timeout);
+        
+        // change chunk size
+        ++cs;
+        if (cs==csend) {
+            cs = gChunkSize;
+        }
+    }
+    
+}
+
+FILE* OpenSDFile(const char* name, const char* mode) {
+    // TODO: check if we have memory?
+    std::string fn(name);
+    if (strncmp(name, kSDsubDir, strlen(kSDsubDir))!=0) {
+        // filename lacks directory
+        fn = kSDsubDir;
+        fn += "/";
+        fn += name;
+    }
+#ifdef DEBUG
+    printf("OpenSDFile: %s, mode %s\r\n",fn.c_str(),mode);
+#endif
+    return fopen(fn.c_str(), mode);
+}
+
+void SendAllFiles(const int timeout) {
+
+    DIR* d;
+    struct dirent* dent;
+    
+    if ( (d = opendir( kSDsubDir ))!=NULL ) {
+        FILE* f;
+        while ( (dent = readdir(d))!=NULL ) {
+            if (strncmp(dent->d_name, kFileTag, strlen(kFileTag))==0) {
+                f = OpenSDFile(dent->d_name, "rb");
+                SendAll(dent->d_name, strlen(dent->d_name), timeout);
+                SendData(f, timeout);
+                fclose(f);
+            }
+        }
+        closedir(d);
+    }
+}
+
+bool IsTimedOut(const int timeout_clock) {
+    if (timeout_clock==0) {
+        // for not obeying timeout option
+        return false;
+    } else {
+        const int ct = time(0);
+        if ( (ct==0) ||
+             (abs(static_cast<double>(timeout_clock-ct))>kSecsPerDay) ) {
+            // clock problems! timeout now.
+#ifdef DEBUG
+            printf("clock problem. timing out\r\n");
+#endif            
+            return true;
+        } else {
+            const bool rt = (ct>timeout_clock);
+#ifdef DEBUG
+            if (rt) {
+                printf("timing out.\r\n");
+            }
+#endif
+            return rt;
+        }
+    }
+}
+
+void dispStrBytes(const char* const s, const int len) {
+    const char* c = s;
+    for (int i=0; i<len; ++i, ++c) {
+        if (*c>0x1F && *c<0x7F) {
+            printf("%c", *c);
+        } else {
+            printf(".x%02x.", *c);
+        }
+    }
+}
+
+int DoIO(char* const data,
+         const int length,
+         const int timeout_clock,
+         TCPSendRecv fcn) {
+    // TODO: if B64, must return number of bytes of raw (non encoded) message
+#ifdef DEBUG
+    printf("DoIO data:\r\n");
+    dispStrBytes(data, length);
+    printf("\r\n");
+#endif
+    int res=0;
+    int b=0;
+    while ( (length>b) ) {
+        if (IsTimedOut(timeout_clock)) {
+#ifdef DEBUG
+            printf("DoIO timing out\r\n");
+#endif
+            break;
+        }
+        res = CALL_MEMBER_FN(*gSock, fcn)(data+b, length-b);
+        switch (res) {
+            case -1:
+                // TODO: how to check the error?
+                continue;
+            case 0:
+                return res;
+            default:
+                b += res;
+        };
+        //wait_ms(100);
+    }
+#if defined(DEBUG) || defined(PRINT_DOIO_RESULT)
+    printf("return b=%d\r\n",b);
+#endif
+    return b; // timeout
+}
+
+int ReceiveAll(char* const buf, const int mlen, const int timeout_clock) {
+    // use regular receive; DoIO will do a receive_all but use our timeout
+    return DoIO(buf, mlen, timeout_clock, &TCPSocketConnection::receive);
+}
+
+int SendAll(char* const data, const int length, const int timeout_clock) {
+    // use regular send; DoIO will do a send_all but use our timeout
+    return DoIO(data, length, timeout_clock, &TCPSocketConnection::send);
+}