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

Committer:
uci1
Date:
Sat Sep 22 04:25:21 2012 +0000
Revision:
1:6b90cbfe0c9e
Parent:
0:53afc51b78a9
fixed return of DoIO in case of a send/recv returning 0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
uci1 0:53afc51b78a9 1 #include "mbed.h"
uci1 0:53afc51b78a9 2
uci1 0:53afc51b78a9 3 #include "SDFileSystem.h"
uci1 0:53afc51b78a9 4 #include "TCPSocketConnection.h"
uci1 0:53afc51b78a9 5 #include "EthernetInterface.h"
uci1 0:53afc51b78a9 6 #include "string"
uci1 0:53afc51b78a9 7 #include "fakeData.h"
uci1 0:53afc51b78a9 8
uci1 0:53afc51b78a9 9 //#define DEBUG // turn on debug output if defined (note this slows down processing due to serial baud rate!)
uci1 0:53afc51b78a9 10 //#define PRINT_DOIO_RESULT // print the number of bytes DoIO returns
uci1 0:53afc51b78a9 11
uci1 0:53afc51b78a9 12 // if this is defined, read files starting with "S" from the SD card
uci1 0:53afc51b78a9 13 // otherwise use the fake data in fakeData.h (from memory)
uci1 0:53afc51b78a9 14 //#define USE_DATA_FROM_SD
uci1 0:53afc51b78a9 15
uci1 0:53afc51b78a9 16 DigitalOut led1(LED1);
uci1 0:53afc51b78a9 17 DigitalOut led2(LED2);
uci1 0:53afc51b78a9 18 DigitalOut led3(LED3);
uci1 0:53afc51b78a9 19 DigitalOut led4(LED4);
uci1 0:53afc51b78a9 20
uci1 0:53afc51b78a9 21 static const char* kRserv = "128.195.204.151";
uci1 0:53afc51b78a9 22 static const unsigned short kRport = 6666;
uci1 0:53afc51b78a9 23
uci1 0:53afc51b78a9 24 static const char* kMyIp = "128.195.204.148";
uci1 0:53afc51b78a9 25 static const char* kMyMask = "255.255.255.0";
uci1 0:53afc51b78a9 26 static const char* kMyGate = "128.195.204.1";
uci1 0:53afc51b78a9 27
uci1 0:53afc51b78a9 28 static const unsigned int kBSTime = 946684800u; // 1/1/2000 00:00:00 UTC
uci1 0:53afc51b78a9 29 static const int kSecsPerDay = 3600*24;
uci1 0:53afc51b78a9 30 static const int kBuffSize = 1024;
uci1 0:53afc51b78a9 31 // all chunks must be smaller than kBuffSize
uci1 0:53afc51b78a9 32 static const int kNCsizes = 5;
uci1 0:53afc51b78a9 33 static const int gChunkSize[kNCsizes] = { 9, 26, 711, 40, 432 };
uci1 0:53afc51b78a9 34 static const int kTotFakeDat = 2097152; // if sending fake data, send 2 MB total
uci1 0:53afc51b78a9 35 static const int kTimeout = 300; // seconds
uci1 0:53afc51b78a9 36
uci1 0:53afc51b78a9 37 static const char* kSDsubDir = "/sd";
uci1 0:53afc51b78a9 38 static const char* kFileTag = "S"; // send files starting with this tag
uci1 0:53afc51b78a9 39
uci1 0:53afc51b78a9 40 static char gBuff[kBuffSize];
uci1 0:53afc51b78a9 41 static SDFileSystem sd(p5, p6, p7, p8, kSDsubDir+1);
uci1 0:53afc51b78a9 42 static LocalFileSystem local("local");
uci1 0:53afc51b78a9 43 static EthernetInterface* gEth(0);
uci1 0:53afc51b78a9 44 static TCPSocketConnection* gSock(0);
uci1 0:53afc51b78a9 45 static Serial gCpu( USBTX, USBRX );
uci1 0:53afc51b78a9 46
uci1 0:53afc51b78a9 47 // function pointer to send, receive, etc
uci1 0:53afc51b78a9 48 typedef int (TCPSocketConnection::*TCPSendRecv)(char*, int);
uci1 0:53afc51b78a9 49 #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
uci1 0:53afc51b78a9 50
uci1 0:53afc51b78a9 51 // forward declarations
uci1 0:53afc51b78a9 52 bool Connect(const int timeout);
uci1 0:53afc51b78a9 53 void SendData(FILE* inf, const int timeout);
uci1 0:53afc51b78a9 54 FILE* OpenSDFile(const char* name, const char* mode);
uci1 0:53afc51b78a9 55 void SendAllFakeData(const int totalBytes, const int timeout);
uci1 0:53afc51b78a9 56 void SendAllFiles(const int timeout);
uci1 0:53afc51b78a9 57 bool IsTimedOut(const int timeout_clock);
uci1 0:53afc51b78a9 58 void dispStrBytes(const char* const s, const int len);
uci1 0:53afc51b78a9 59 int DoIO(char* const data,
uci1 0:53afc51b78a9 60 const int length,
uci1 0:53afc51b78a9 61 const int timeout_clock,
uci1 0:53afc51b78a9 62 TCPSendRecv fcn);
uci1 0:53afc51b78a9 63 int ReceiveAll(char* const buf, const int mlen, const int timeout_clock);
uci1 0:53afc51b78a9 64 int SendAll(char* const data, const int length, const int timeout_clock);
uci1 0:53afc51b78a9 65
uci1 0:53afc51b78a9 66
uci1 0:53afc51b78a9 67 int main() {
uci1 0:53afc51b78a9 68 led1=1;
uci1 0:53afc51b78a9 69 set_time(kBSTime);
uci1 0:53afc51b78a9 70 if (Connect(time(0)+kTimeout)) {
uci1 0:53afc51b78a9 71 led2=1;
uci1 0:53afc51b78a9 72 #ifdef USE_DATA_FROM_SD
uci1 0:53afc51b78a9 73 SendAllFiles(time(0)+kTimeout);
uci1 0:53afc51b78a9 74 #else
uci1 0:53afc51b78a9 75 SendAllFakeData(kTotFakeDat, time(0)+kTimeout);
uci1 0:53afc51b78a9 76 #endif
uci1 0:53afc51b78a9 77 } else {
uci1 0:53afc51b78a9 78 led4=1;
uci1 0:53afc51b78a9 79 }
uci1 0:53afc51b78a9 80 if (gSock!=0) {
uci1 0:53afc51b78a9 81 gSock->close();
uci1 0:53afc51b78a9 82 }
uci1 0:53afc51b78a9 83 if (gEth!=0) {
uci1 0:53afc51b78a9 84 gEth->disconnect();
uci1 0:53afc51b78a9 85 }
uci1 0:53afc51b78a9 86 while (true) {
uci1 0:53afc51b78a9 87 led1=0; wait(0.5); led1=1; wait(0.5);
uci1 0:53afc51b78a9 88 }
uci1 0:53afc51b78a9 89 }
uci1 0:53afc51b78a9 90
uci1 0:53afc51b78a9 91 bool Connect(const int timeout) {
uci1 0:53afc51b78a9 92
uci1 0:53afc51b78a9 93 #ifdef DEBUG
uci1 0:53afc51b78a9 94 printf("Connect\r\n");
uci1 0:53afc51b78a9 95 #endif
uci1 0:53afc51b78a9 96
uci1 0:53afc51b78a9 97 gEth = new EthernetInterface;
uci1 0:53afc51b78a9 98 gSock = new TCPSocketConnection;
uci1 0:53afc51b78a9 99
uci1 0:53afc51b78a9 100 gEth->init(kMyIp, kMyMask, kMyGate);
uci1 0:53afc51b78a9 101
uci1 0:53afc51b78a9 102 bool isConn = false;
uci1 0:53afc51b78a9 103
uci1 0:53afc51b78a9 104 while ( (isConn==false) && (IsTimedOut(timeout)==false) ) {
uci1 0:53afc51b78a9 105 wait_ms(250);
uci1 0:53afc51b78a9 106 isConn = (gEth->connect()==0);
uci1 0:53afc51b78a9 107 }
uci1 0:53afc51b78a9 108 #ifdef DEBUG
uci1 0:53afc51b78a9 109 printf("eth isConn=%d\r\n",(int)isConn);
uci1 0:53afc51b78a9 110 #endif
uci1 0:53afc51b78a9 111
uci1 0:53afc51b78a9 112 isConn=false;
uci1 0:53afc51b78a9 113 while ( (isConn==false) && (IsTimedOut(timeout)==false) ) {
uci1 0:53afc51b78a9 114 wait_ms(250);
uci1 0:53afc51b78a9 115 isConn = (gSock->connect(kRserv, kRport)==0);
uci1 0:53afc51b78a9 116 }
uci1 0:53afc51b78a9 117 #ifdef DEBUG
uci1 0:53afc51b78a9 118 printf("sock isConn=%d\r\n",(int)isConn);
uci1 0:53afc51b78a9 119 #endif
uci1 0:53afc51b78a9 120 return isConn;
uci1 0:53afc51b78a9 121 }
uci1 0:53afc51b78a9 122
uci1 0:53afc51b78a9 123 void SendAllFakeData(const int totalBytes, const int timeout) {
uci1 0:53afc51b78a9 124 // send the fake data in chunks
uci1 0:53afc51b78a9 125
uci1 0:53afc51b78a9 126 const int* const csend = gChunkSize + kNCsizes;
uci1 0:53afc51b78a9 127 const int* cs = gChunkSize;
uci1 0:53afc51b78a9 128
uci1 0:53afc51b78a9 129 int br=0; // bytes read/sent so far
uci1 0:53afc51b78a9 130 int tcs=0; // this chunk size
uci1 0:53afc51b78a9 131 while ( br<totalBytes ) {
uci1 0:53afc51b78a9 132
uci1 0:53afc51b78a9 133 // read a chunk
uci1 0:53afc51b78a9 134 tcs = (*cs < kFakeDataSize) ? (*cs) : kFakeDataSize;
uci1 0:53afc51b78a9 135 memcpy(gBuff, gFakeData, tcs);
uci1 0:53afc51b78a9 136
uci1 0:53afc51b78a9 137 // send this chunk
uci1 0:53afc51b78a9 138 br += SendAll(gBuff, tcs, timeout);
uci1 0:53afc51b78a9 139
uci1 0:53afc51b78a9 140 // change chunk size
uci1 0:53afc51b78a9 141 ++cs;
uci1 0:53afc51b78a9 142 if (cs==csend) {
uci1 0:53afc51b78a9 143 cs = gChunkSize;
uci1 0:53afc51b78a9 144 }
uci1 0:53afc51b78a9 145 }
uci1 0:53afc51b78a9 146 }
uci1 0:53afc51b78a9 147
uci1 0:53afc51b78a9 148 void SendData(FILE* inf, const int timeout) {
uci1 0:53afc51b78a9 149 // send the SD card data in chunks
uci1 0:53afc51b78a9 150
uci1 0:53afc51b78a9 151 // store position in file so we can go back to it afterwards
uci1 0:53afc51b78a9 152 const int fpos = ftell(inf);
uci1 0:53afc51b78a9 153 if (fpos>0) {
uci1 0:53afc51b78a9 154 fseek(inf, 0, SEEK_SET);
uci1 0:53afc51b78a9 155 }
uci1 0:53afc51b78a9 156 // how many bytes?
uci1 0:53afc51b78a9 157 fseek(inf, 0, SEEK_END); // go to end
uci1 0:53afc51b78a9 158 const int fend = ftell(inf);
uci1 0:53afc51b78a9 159 fseek(inf, 0, SEEK_SET); // go to start
uci1 0:53afc51b78a9 160 #ifdef DEBUG
uci1 0:53afc51b78a9 161 printf("fend=%d\r\n",fend);
uci1 0:53afc51b78a9 162 printf("fpos=%d\r\n",fpos);
uci1 0:53afc51b78a9 163 #endif
uci1 0:53afc51b78a9 164
uci1 0:53afc51b78a9 165 const int* const csend = gChunkSize + kNCsizes;
uci1 0:53afc51b78a9 166 const int* cs = gChunkSize;
uci1 0:53afc51b78a9 167
uci1 0:53afc51b78a9 168 int br=0; // bytes read/sent so far
uci1 0:53afc51b78a9 169 int tcs=0; // this chunk size
uci1 0:53afc51b78a9 170 while ( br<fend ) {
uci1 0:53afc51b78a9 171
uci1 0:53afc51b78a9 172 // read a chunk or the remainder of the file
uci1 0:53afc51b78a9 173 tcs = ((br+(*cs))<fend) ? (*cs) : (fend-br);
uci1 0:53afc51b78a9 174 fread(gBuff, tcs, 1, inf);
uci1 0:53afc51b78a9 175
uci1 0:53afc51b78a9 176 // send this chunk
uci1 0:53afc51b78a9 177 br += SendAll(gBuff, tcs, timeout);
uci1 0:53afc51b78a9 178
uci1 0:53afc51b78a9 179 // change chunk size
uci1 0:53afc51b78a9 180 ++cs;
uci1 0:53afc51b78a9 181 if (cs==csend) {
uci1 0:53afc51b78a9 182 cs = gChunkSize;
uci1 0:53afc51b78a9 183 }
uci1 0:53afc51b78a9 184 }
uci1 0:53afc51b78a9 185
uci1 0:53afc51b78a9 186 }
uci1 0:53afc51b78a9 187
uci1 0:53afc51b78a9 188 FILE* OpenSDFile(const char* name, const char* mode) {
uci1 0:53afc51b78a9 189 // TODO: check if we have memory?
uci1 0:53afc51b78a9 190 std::string fn(name);
uci1 0:53afc51b78a9 191 if (strncmp(name, kSDsubDir, strlen(kSDsubDir))!=0) {
uci1 0:53afc51b78a9 192 // filename lacks directory
uci1 0:53afc51b78a9 193 fn = kSDsubDir;
uci1 0:53afc51b78a9 194 fn += "/";
uci1 0:53afc51b78a9 195 fn += name;
uci1 0:53afc51b78a9 196 }
uci1 0:53afc51b78a9 197 #ifdef DEBUG
uci1 0:53afc51b78a9 198 printf("OpenSDFile: %s, mode %s\r\n",fn.c_str(),mode);
uci1 0:53afc51b78a9 199 #endif
uci1 0:53afc51b78a9 200 return fopen(fn.c_str(), mode);
uci1 0:53afc51b78a9 201 }
uci1 0:53afc51b78a9 202
uci1 0:53afc51b78a9 203 void SendAllFiles(const int timeout) {
uci1 0:53afc51b78a9 204
uci1 0:53afc51b78a9 205 DIR* d;
uci1 0:53afc51b78a9 206 struct dirent* dent;
uci1 0:53afc51b78a9 207
uci1 0:53afc51b78a9 208 if ( (d = opendir( kSDsubDir ))!=NULL ) {
uci1 0:53afc51b78a9 209 FILE* f;
uci1 0:53afc51b78a9 210 while ( (dent = readdir(d))!=NULL ) {
uci1 0:53afc51b78a9 211 if (strncmp(dent->d_name, kFileTag, strlen(kFileTag))==0) {
uci1 0:53afc51b78a9 212 f = OpenSDFile(dent->d_name, "rb");
uci1 0:53afc51b78a9 213 SendAll(dent->d_name, strlen(dent->d_name), timeout);
uci1 0:53afc51b78a9 214 SendData(f, timeout);
uci1 0:53afc51b78a9 215 fclose(f);
uci1 0:53afc51b78a9 216 }
uci1 0:53afc51b78a9 217 }
uci1 0:53afc51b78a9 218 closedir(d);
uci1 0:53afc51b78a9 219 }
uci1 0:53afc51b78a9 220 }
uci1 0:53afc51b78a9 221
uci1 0:53afc51b78a9 222 bool IsTimedOut(const int timeout_clock) {
uci1 0:53afc51b78a9 223 if (timeout_clock==0) {
uci1 0:53afc51b78a9 224 // for not obeying timeout option
uci1 0:53afc51b78a9 225 return false;
uci1 0:53afc51b78a9 226 } else {
uci1 0:53afc51b78a9 227 const int ct = time(0);
uci1 0:53afc51b78a9 228 if ( (ct==0) ||
uci1 0:53afc51b78a9 229 (abs(static_cast<double>(timeout_clock-ct))>kSecsPerDay) ) {
uci1 0:53afc51b78a9 230 // clock problems! timeout now.
uci1 0:53afc51b78a9 231 #ifdef DEBUG
uci1 0:53afc51b78a9 232 printf("clock problem. timing out\r\n");
uci1 0:53afc51b78a9 233 #endif
uci1 0:53afc51b78a9 234 return true;
uci1 0:53afc51b78a9 235 } else {
uci1 0:53afc51b78a9 236 const bool rt = (ct>timeout_clock);
uci1 0:53afc51b78a9 237 #ifdef DEBUG
uci1 0:53afc51b78a9 238 if (rt) {
uci1 0:53afc51b78a9 239 printf("timing out.\r\n");
uci1 0:53afc51b78a9 240 }
uci1 0:53afc51b78a9 241 #endif
uci1 0:53afc51b78a9 242 return rt;
uci1 0:53afc51b78a9 243 }
uci1 0:53afc51b78a9 244 }
uci1 0:53afc51b78a9 245 }
uci1 0:53afc51b78a9 246
uci1 0:53afc51b78a9 247 void dispStrBytes(const char* const s, const int len) {
uci1 0:53afc51b78a9 248 const char* c = s;
uci1 0:53afc51b78a9 249 for (int i=0; i<len; ++i, ++c) {
uci1 0:53afc51b78a9 250 if (*c>0x1F && *c<0x7F) {
uci1 0:53afc51b78a9 251 printf("%c", *c);
uci1 0:53afc51b78a9 252 } else {
uci1 0:53afc51b78a9 253 printf(".x%02x.", *c);
uci1 0:53afc51b78a9 254 }
uci1 0:53afc51b78a9 255 }
uci1 0:53afc51b78a9 256 }
uci1 0:53afc51b78a9 257
uci1 0:53afc51b78a9 258 int DoIO(char* const data,
uci1 0:53afc51b78a9 259 const int length,
uci1 0:53afc51b78a9 260 const int timeout_clock,
uci1 0:53afc51b78a9 261 TCPSendRecv fcn) {
uci1 0:53afc51b78a9 262 // TODO: if B64, must return number of bytes of raw (non encoded) message
uci1 0:53afc51b78a9 263 #ifdef DEBUG
uci1 0:53afc51b78a9 264 printf("DoIO data:\r\n");
uci1 0:53afc51b78a9 265 dispStrBytes(data, length);
uci1 0:53afc51b78a9 266 printf("\r\n");
uci1 0:53afc51b78a9 267 #endif
uci1 0:53afc51b78a9 268 int res=0;
uci1 0:53afc51b78a9 269 int b=0;
uci1 0:53afc51b78a9 270 while ( (length>b) ) {
uci1 0:53afc51b78a9 271 if (IsTimedOut(timeout_clock)) {
uci1 0:53afc51b78a9 272 #ifdef DEBUG
uci1 0:53afc51b78a9 273 printf("DoIO timing out\r\n");
uci1 0:53afc51b78a9 274 #endif
uci1 0:53afc51b78a9 275 break;
uci1 0:53afc51b78a9 276 }
uci1 0:53afc51b78a9 277 res = CALL_MEMBER_FN(*gSock, fcn)(data+b, length-b);
uci1 0:53afc51b78a9 278 switch (res) {
uci1 0:53afc51b78a9 279 case -1:
uci1 0:53afc51b78a9 280 // TODO: how to check the error?
uci1 0:53afc51b78a9 281 continue;
uci1 0:53afc51b78a9 282 case 0:
uci1 1:6b90cbfe0c9e 283 return b;
uci1 0:53afc51b78a9 284 default:
uci1 0:53afc51b78a9 285 b += res;
uci1 0:53afc51b78a9 286 };
uci1 0:53afc51b78a9 287 //wait_ms(100);
uci1 0:53afc51b78a9 288 }
uci1 0:53afc51b78a9 289 #if defined(DEBUG) || defined(PRINT_DOIO_RESULT)
uci1 0:53afc51b78a9 290 printf("return b=%d\r\n",b);
uci1 0:53afc51b78a9 291 #endif
uci1 0:53afc51b78a9 292 return b; // timeout
uci1 0:53afc51b78a9 293 }
uci1 0:53afc51b78a9 294
uci1 0:53afc51b78a9 295 int ReceiveAll(char* const buf, const int mlen, const int timeout_clock) {
uci1 0:53afc51b78a9 296 // use regular receive; DoIO will do a receive_all but use our timeout
uci1 0:53afc51b78a9 297 return DoIO(buf, mlen, timeout_clock, &TCPSocketConnection::receive);
uci1 0:53afc51b78a9 298 }
uci1 0:53afc51b78a9 299
uci1 0:53afc51b78a9 300 int SendAll(char* const data, const int length, const int timeout_clock) {
uci1 0:53afc51b78a9 301 // use regular send; DoIO will do a send_all but use our timeout
uci1 0:53afc51b78a9 302 return DoIO(data, length, timeout_clock, &TCPSocketConnection::send);
uci1 0:53afc51b78a9 303 }