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
main.cpp
- Committer:
- uci1
- Date:
- 2012-09-22
- Revision:
- 1:6b90cbfe0c9e
- Parent:
- 0:53afc51b78a9
File content as of revision 1:6b90cbfe0c9e:
#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 b; 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); }