00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "../msg/msg.h"
00025 #include "../utils/utils.h"
00026 #include <dashel/dashel.h>
00027 #include "HexFile.h"
00028 #include <iostream>
00029 #include <fstream>
00030 #include <vector>
00031 #include <iterator>
00032 #include <cassert>
00033 #include <cstring>
00034
00035 namespace Aseba
00036 {
00037 using namespace Dashel;
00038 using namespace std;
00039
00041 void dumpCommandList(ostream &stream)
00042 {
00043 stream << "* presence : broadcast presence message\n";
00044 stream << "* usermsg: user message [type] [length in 16 bit words]\n";
00045 stream << "* rdpage : bootloader read page [dest] [page number]\n";
00046 stream << "* whex : write hex file [dest] [file name] [reset]\n";
00047 stream << "* rhex : read hex file [source] [file name]\n";
00048 stream << "* eb: exit from bootloader, go back into user mode [dest]\n";
00049 stream << "* sb: switch into bootloader: reboot node, then enter bootloader for a while [dest]\n";
00050 stream << "* sleep: put the vm to sleep [dest]\n";
00051 }
00052
00054 void dumpHelp(ostream &stream, const char *programName)
00055 {
00056 stream << "Aseba cmd, send message over the aseba network, usage:\n";
00057 stream << programName << " [-t target] [cmd destId (args)] ... [cmd destId (args)]\n";
00058 stream << "where cmd is one af the following:\n";
00059 dumpCommandList(stream);
00060 }
00061
00063 void errorMissingArgument(const char *programName)
00064 {
00065 cerr << "Error, missing argument.\n";
00066 dumpHelp(cerr, programName);
00067 exit(4);
00068 }
00069
00071 void errorUnknownCommand(const char *cmd)
00072 {
00073 cerr << "Error, unknown command " << cmd << endl;
00074 cerr << "Known commands are:\n";
00075 dumpCommandList(cerr);
00076 exit(5);
00077 }
00078
00080 void errorReadPage(int pageNumber)
00081 {
00082 cerr << "Error, can't read page " << pageNumber << endl;
00083 exit(6);
00084 }
00085
00087 void errorOpenFile(const char *fileName)
00088 {
00089 cerr << "Error, can't open file " << fileName << endl;
00090 exit(7);
00091 }
00092
00094 void errorWriteFile(const char *fileName)
00095 {
00096 cerr << "Error, can't write file " << fileName << endl;
00097 exit(8);
00098 }
00099
00101 void errorServerDisconnected()
00102 {
00103 cerr << "Server closed connection before command was completely sent." << endl;
00104 exit(9);
00105 }
00106
00108 void errorHexFile(const string &message)
00109 {
00110 cerr << "HEX file error: " << message << endl;
00111 exit(10);
00112 }
00113
00115 void errorWritePage(unsigned pageIndex)
00116 {
00117 cerr << "Error while writing page " << pageIndex << endl;
00118 exit(11);
00119 }
00120
00122 void errorReadPage(unsigned pageIndex)
00123 {
00124 cerr << "Error while reading page " << pageIndex << endl;
00125 exit(12);
00126 }
00127
00129 void errorReadPage(unsigned pageIndex, unsigned pagesStart, unsigned pagesCount)
00130 {
00131 cerr << "Error, page index " << pageIndex << " out of page range [ " << pagesStart << " : " << pagesStart + pagesCount << " ]" << endl;
00132 exit(13);
00133 }
00134
00136 class BootloaderInterface
00137 {
00138 public:
00140 BootloaderInterface(Stream* stream, int dest) :
00141 stream(stream),
00142 dest(dest)
00143 {
00144
00145
00146 }
00147
00149 int getPageSize() { return pageSize; }
00150
00152 bool readPage(unsigned pageNumber, uint8* data)
00153 {
00154 if ((pageNumber < pagesStart) || (pageNumber >= pagesStart + pagesCount))
00155 {
00156 errorReadPage(pageNumber, pagesStart, pagesCount);
00157 return false;
00158 }
00159
00160
00161 BootloaderReadPage message;
00162 message.dest = dest;
00163 message.pageNumber = pageNumber;
00164 message.serialize(stream);
00165 stream->flush();
00166 unsigned dataRead = 0;
00167
00168
00169 while (true)
00170 {
00171 Message *message = Message::receive(stream);
00172
00173
00174 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message);
00175 if (ackMessage && (ackMessage->source == dest))
00176 {
00177 uint16 errorCode = ackMessage->errorCode;
00178 delete message;
00179 if (errorCode == BootloaderAck::SUCCESS)
00180 {
00181 if (dataRead < pageSize)
00182 cerr << "Warning, got acknowledgement but page not fully read (" << dataRead << "/" << pageSize << ") bytes.\n";
00183 return true;
00184 }
00185 else
00186 return false;
00187 }
00188
00189
00190 BootloaderDataRead *dataMessage = dynamic_cast<BootloaderDataRead *>(message);
00191 if (dataMessage && (dataMessage->source == dest))
00192 {
00193 if (dataRead >= pageSize)
00194 cerr << "Warning, reading oversized page (" << dataRead << "/" << pageSize << ") bytes.\n";
00195 copy(dataMessage->data, dataMessage->data + sizeof(dataMessage->data), data);
00196 data += sizeof(dataMessage->data);
00197 dataRead += sizeof(dataMessage->data);
00198 cout << "Page read so far (" << dataRead << "/" << pageSize << ") bytes.\n";
00199 }
00200
00201 delete message;
00202 }
00203
00204 return true;
00205 }
00206
00208 bool writePage(int pageNumber, const uint8 *data)
00209 {
00210
00211 BootloaderWritePage writePage;
00212 writePage.dest = dest;
00213 writePage.pageNumber = pageNumber;
00214 writePage.serialize(stream);
00215 stream->flush();
00216
00217 cout << "Writing page " << pageNumber << endl;
00218
00219 while (true)
00220 {
00221 Message *message = Message::receive(stream);
00222
00223
00224 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message);
00225 if (ackMessage && (ackMessage->source == dest))
00226 {
00227 uint16 errorCode = ackMessage->errorCode;
00228 delete message;
00229 if(errorCode == BootloaderAck::SUCCESS)
00230 break;
00231 else
00232 return false;
00233 }
00234
00235 delete message;
00236 }
00237
00238
00239 for (unsigned dataWritten = 0; dataWritten < pageSize;)
00240 {
00241 BootloaderPageDataWrite pageData;
00242 pageData.dest = dest;
00243 copy(data + dataWritten, data + dataWritten + sizeof(pageData.data), pageData.data);
00244 pageData.serialize(stream);
00245 dataWritten += sizeof(pageData.data);
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 }
00269
00270 stream->flush();
00271
00272 while (true)
00273 {
00274 Message *message = Message::receive(stream);
00275
00276
00277 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message);
00278 if (ackMessage && (ackMessage->source == dest))
00279 {
00280 uint16 errorCode = ackMessage->errorCode;
00281 delete message;
00282 if(errorCode == BootloaderAck::SUCCESS)
00283 break;
00284 else
00285 return false;
00286 }
00287
00288 delete message;
00289 }
00290
00291 cout << "done" << endl;
00292 return true;
00293 }
00294
00296 void writeHex(const string &fileName, bool reset)
00297 {
00298
00299 HexFile hexFile;
00300 hexFile.read(fileName);
00301
00302 if (reset)
00303 {
00304 Reboot msg(dest);
00305 msg.serialize(stream);
00306 stream->flush();
00307 }
00308
00309 while (true)
00310 {
00311 Message *message = Message::receive(stream);
00312 BootloaderDescription *bDescMessage = dynamic_cast<BootloaderDescription *>(message);
00313 if (bDescMessage && (bDescMessage->source == dest))
00314 {
00315 pageSize = bDescMessage->pageSize;
00316 pagesStart = bDescMessage->pagesStart;
00317 pagesCount = bDescMessage->pagesCount;
00318 delete message;
00319 break;
00320 }
00321 delete message;
00322 }
00323
00324
00325 typedef map<uint32, vector<uint8> > PageMap;
00326 PageMap pageMap;
00327 for (HexFile::ChunkMap::iterator it = hexFile.data.begin(); it != hexFile.data.end(); it ++)
00328 {
00329
00330 unsigned chunkAddress = it->first;
00331
00332 unsigned chunkDataIndex = 0;
00333
00334 unsigned chunkSize = it->second.size();
00335
00336
00337 do
00338 {
00339
00340 unsigned pageIndex = (chunkAddress + chunkDataIndex) / pageSize;
00341
00342 unsigned byteIndex = (chunkAddress + chunkDataIndex) % pageSize;
00343
00344
00345 if (pageMap.find(pageIndex) == pageMap.end())
00346 {
00347
00348 pageMap[pageIndex] = vector<uint8>(pageSize, (uint8)0);
00349 }
00350
00351 unsigned amountToCopy = min(pageSize - byteIndex, chunkSize - chunkDataIndex);
00352 copy(it->second.begin() + chunkDataIndex, it->second.begin() + chunkDataIndex + amountToCopy, pageMap[pageIndex].begin() + byteIndex);
00353
00354
00355 chunkDataIndex += amountToCopy;
00356 }
00357 while (chunkDataIndex < chunkSize);
00358 }
00359
00360
00361 for (PageMap::iterator it = pageMap.begin(); it != pageMap.end(); it ++)
00362 {
00363 unsigned pageIndex = it->first;
00364 if ((pageIndex >= pagesStart) && (pageIndex < pagesStart + pagesCount))
00365 if (!writePage(pageIndex, &it->second[0]))
00366 errorWritePage(pageIndex);
00367 }
00368
00369 if (reset)
00370 {
00371 BootloaderReset msg(dest);
00372 msg.serialize(stream);
00373 stream->flush();
00374 }
00375 }
00376
00378 void readHex(const string &fileName)
00379 {
00380 HexFile hexFile;
00381
00382
00383 unsigned address = pagesStart * pageSize;
00384 hexFile.data[address] = vector<uint8>();
00385 hexFile.data[address].reserve(pagesCount * pageSize);
00386
00387
00388 for (unsigned page = pagesStart; page < pagesCount; page++)
00389 {
00390 vector<uint8> buffer((uint8)0, pageSize);
00391
00392 if (!readPage(page, &buffer[0]))
00393 errorReadPage(page);
00394
00395 copy(&buffer[0], &buffer[pageSize], back_inserter(hexFile.data[address]));
00396 }
00397
00398
00399 hexFile.write(fileName);
00400 }
00401
00402 protected:
00403 Stream* stream;
00404 int dest;
00405 unsigned pageSize;
00406 unsigned pagesStart;
00407 unsigned pagesCount;
00408 };
00409
00411 int processCommand(Stream* stream, int argc, char *argv[])
00412 {
00413 const char *cmd = argv[0];
00414 int argEaten = 0;
00415
00416 if (strcmp(cmd, "presence") == 0)
00417 {
00418 GetDescription message;
00419 message.serialize(stream);
00420 stream->flush();
00421 }
00422 else if (strcmp(cmd, "usermsg") == 0)
00423 {
00424
00425 if (argc < 3)
00426 errorMissingArgument(argv[0]);
00427 argEaten = 2;
00428 uint16 type = atoi(argv[1]);
00429 uint16 length = atoi(argv[2]);
00430
00431 UserMessage::DataVector data(length);
00432 for (size_t i = 0; i < length; i++)
00433 data[i] = i;
00434
00435 UserMessage message(type, data);
00436 message.serialize(stream);
00437 stream->flush();
00438 }
00439 else if (strcmp(cmd, "rdpage") == 0)
00440 {
00441
00442 if (argc < 3)
00443 errorMissingArgument(argv[0]);
00444 argEaten = 2;
00445
00446 BootloaderInterface bootloader(stream, atoi(argv[1]));
00447
00448 vector<uint8> data(bootloader.getPageSize());
00449 if (bootloader.readPage(atoi(argv[2]), &data[0]))
00450 {
00451 ofstream file("page.bin");
00452 if (file.good())
00453 copy(data.begin(), data.end(), ostream_iterator<uint8>(file));
00454 else
00455 errorOpenFile("page.bin");
00456 }
00457 else
00458 errorReadPage(atoi(argv[2]));
00459 }
00460 else if (strcmp(cmd, "whex") == 0)
00461 {
00462 bool reset = 0;
00463
00464 if (argc < 3)
00465 errorMissingArgument(argv[0]);
00466 argEaten = 2;
00467
00468 if (argc > 3 && !strcmp(argv[3], "reset"))
00469 {
00470 reset = 1;
00471 argEaten = 3;
00472 }
00473
00474
00475 try
00476 {
00477 BootloaderInterface bootloader(stream, atoi(argv[1]));
00478 bootloader.writeHex(argv[2], reset);
00479 }
00480 catch (HexFile::Error &e)
00481 {
00482 errorHexFile(e.toString());
00483 }
00484 }
00485 else if (strcmp(cmd, "rhex") == 0)
00486 {
00487
00488 if (argc < 3)
00489 errorMissingArgument(argv[0]);
00490 argEaten = 2;
00491
00492
00493 try
00494 {
00495 BootloaderInterface bootloader(stream, atoi(argv[1]));
00496 bootloader.readHex(argv[2]);
00497 }
00498 catch (HexFile::Error &e)
00499 {
00500 errorHexFile(e.toString());
00501 }
00502 }
00503 else if (strcmp(cmd, "eb") == 0)
00504 {
00505 uint16 dest;
00506
00507 if(argc < 2)
00508 errorMissingArgument(argv[0]);
00509 argEaten = 1;
00510
00511 dest = atoi(argv[1]);
00512
00513 BootloaderReset msg(dest);
00514 msg.serialize(stream);
00515 stream->flush();
00516
00517
00518
00519
00520 while (true)
00521 {
00522 Message *message = Message::receive(stream);
00523
00524
00525 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message);
00526 if (ackMessage && (ackMessage->source == dest))
00527 {
00528 cout << "Device is now in user-code" << endl;
00529 delete message;
00530 break;
00531 }
00532
00533
00534
00535 delete message;
00536 }
00537 }
00538 else if (strcmp(cmd, "sb") == 0)
00539 {
00540 uint16 dest;
00541
00542 if(argc < 2)
00543 errorMissingArgument(argv[0]);
00544 argEaten = 1;
00545
00546 dest = atoi(argv[1]);
00547
00548 Reboot msg(dest);
00549 msg.serialize(stream);
00550 stream->flush();
00551 }
00552 else if (strcmp(cmd, "sleep") == 0)
00553 {
00554 uint16 dest;
00555 if(argc < 2)
00556 errorMissingArgument(argv[0]);
00557 argEaten = 1;
00558
00559 dest = atoi(argv[1]);
00560
00561 Sleep msg(dest);
00562 msg.serialize(stream);
00563 stream->flush();
00564 } else
00565 errorUnknownCommand(cmd);
00566
00567 return argEaten;
00568 }
00569 }
00570
00571 int main(int argc, char *argv[])
00572 {
00573 const char *target = ASEBA_DEFAULT_TARGET;
00574 int argCounter = 1;
00575
00576 while (argCounter < argc)
00577 {
00578 const char *arg = argv[argCounter];
00579 if (strcmp(arg, "-t") == 0)
00580 {
00581 if (++argCounter < argc)
00582 target = argv[argCounter];
00583 else
00584 Aseba::errorMissingArgument(argv[0]);
00585 }
00586 else if ((strcmp(arg, "-h") == 0) || (strcmp(arg, "--help") == 0))
00587 {
00588 Aseba::dumpHelp(std::cout, argv[0]);
00589 return 0;
00590 }
00591 else
00592 {
00593 Dashel::Hub client;
00594 Dashel::Stream* stream = client.connect(target);
00595 assert(stream);
00596
00597
00598 try
00599 {
00600 argCounter += Aseba::processCommand(stream, argc - argCounter, &argv[argCounter]);
00601 stream->flush();
00602 }
00603 catch (Dashel::DashelException e)
00604 {
00605 Aseba::errorServerDisconnected();
00606 }
00607 }
00608 argCounter++;
00609 }
00610 return 0;
00611 }
00612