00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "../common/consts.h"
00022 #include "../msg/msg.h"
00023 #include "../utils/utils.h"
00024 #include "../utils/HexFile.h"
00025 #include "../utils/FormatableString.h"
00026 #include "../utils/BootloaderInterface.h"
00027 #include <dashel/dashel.h>
00028 #include "../transport/dashel_plugins/dashel-plugins.h"
00029 #include <iostream>
00030 #include <fstream>
00031 #include <vector>
00032 #include <iterator>
00033 #include <cassert>
00034 #include <cstring>
00035 #include <memory>
00036
00037 namespace Aseba
00038 {
00039 using namespace Dashel;
00040 using namespace std;
00041
00043 void dumpCommandList(ostream &stream)
00044 {
00045 stream << "* presence : broadcast presence message\n";
00046 stream << "* usermsg: user message [type] [word0] ... [wordN]\n";
00047 stream << "* rdpage : bootloader read page [dest] [page number]\n";
00048 stream << "* rdpageusb : bootloader read page usb [dest] [page number]\n";
00049 stream << "* whex : write hex file [dest] [file name] [reset]\n";
00050 stream << "* rhex : read hex file [source] [file name]\n";
00051 stream << "* eb: exit from bootloader, go back into user mode [dest]\n";
00052 stream << "* sb: switch into bootloader: reboot node, then enter bootloader for a while [dest]\n";
00053 stream << "* sleep: put the vm to sleep [dest]\n";
00054 stream << "* wusb : write hex file to [dest] [file name] [reset]\n";
00055 }
00056
00058 void dumpHelp(ostream &stream, const char *programName)
00059 {
00060 stream << "Aseba cmd, send message over the aseba network, usage:\n";
00061 stream << programName << " [-t target] [cmd destId (args)] ... [cmd destId (args)]\n";
00062 stream << "where cmd is one af the following:\n";
00063 dumpCommandList(stream);
00064 stream << std::endl;
00065 stream << "Other options:\n";
00066 stream << " -h, --help : shows this help\n";
00067 stream << " -V, --version : shows the version number\n";
00068 stream << "Report bugs to: aseba-dev@gna.org" << std::endl;
00069 }
00070
00072 void dumpVersion(std::ostream &stream)
00073 {
00074 stream << "Aseba cmd " << ASEBA_VERSION << std::endl;
00075 stream << "Aseba protocol " << ASEBA_PROTOCOL_VERSION << std::endl;
00076 stream << "Licence LGPLv3: GNU LGPL version 3 <http://www.gnu.org/licenses/lgpl.html>\n";
00077 }
00078
00080 void errorMissingArgument(const char *programName)
00081 {
00082 cerr << "Error, missing argument.\n";
00083 dumpHelp(cerr, programName);
00084 exit(4);
00085 }
00086
00088 void errorUnknownCommand(const char *cmd)
00089 {
00090 cerr << "Error, unknown command " << cmd << endl;
00091 cerr << "Known commands are:\n";
00092 dumpCommandList(cerr);
00093 exit(5);
00094 }
00095
00097 void errorReadPage(int pageNumber)
00098 {
00099 cerr << "Error, can't read page " << pageNumber << endl;
00100 exit(6);
00101 }
00102
00104 void errorOpenFile(const char *fileName)
00105 {
00106 cerr << "Error, can't open file " << fileName << endl;
00107 exit(7);
00108 }
00109
00111 void errorServerDisconnected()
00112 {
00113 cerr << "Server closed connection before command was completely sent." << endl;
00114 exit(9);
00115 }
00116
00118 void errorHexFile(const string &message)
00119 {
00120 cerr << "HEX file error: " << message << endl;
00121 exit(10);
00122 }
00123
00125 void errorBootloader(const string& message)
00126 {
00127 cerr << "Error while interfacing with bootloader: " << message << endl;
00128 exit(9);
00129 }
00130
00131
00132 class CmdBootloaderInterface:public BootloaderInterface
00133 {
00134 public:
00135 CmdBootloaderInterface(Stream* stream, int dest):
00136 BootloaderInterface(stream, dest)
00137 {}
00138
00139 protected:
00140
00141 virtual void writePageStart(unsigned pageNumber, const uint8* data, bool simple)
00142 {
00143 cout << "Writing page " << pageNumber << "... ";
00144 cout.flush();
00145
00146 }
00147
00148 virtual void writePageWaitAck()
00149 {
00150 cout << "Waiting ack ... ";
00151 cout.flush();
00152 }
00153
00154 virtual void writePageSuccess()
00155 {
00156 cout << "Success" << endl;
00157 }
00158
00159 virtual void writePageFailure()
00160 {
00161 cout << "Failure" << endl;
00162 }
00163
00164 virtual void writeHexStart(const string &fileName, bool reset, bool simple)
00165 {
00166 cout << "Flashing " << fileName << endl;
00167 }
00168
00169 virtual void writeHexEnteringBootloader()
00170 {
00171 cout << "Entering bootloader" << endl;
00172 }
00173
00174 virtual void writeHexGotDescription(unsigned pagesCount)
00175 {
00176 cout << "In bootloader, about to write " << pagesCount << " pages" << endl;
00177 }
00178
00179 virtual void writeHexWritten()
00180 {
00181 cout << "Write completed" << endl;
00182 }
00183
00184 virtual void writeHexExitingBootloader()
00185 {
00186 cout << "Exiting bootloader" << endl;
00187 }
00188
00189 virtual void errorWritePageNonFatal(unsigned pageNumber)
00190 {
00191 cerr << "Warning, error while writing page " << pageNumber << ", continuing ..." << endl;
00192 }
00193 };
00194
00196 int processCommand(Stream* stream, int argc, char *argv[])
00197 {
00198 const char *cmd = argv[0];
00199 int argEaten = 0;
00200
00201 if (strcmp(cmd, "presence") == 0)
00202 {
00203 GetDescription message;
00204 message.serialize(stream);
00205 stream->flush();
00206 }
00207 else if (strcmp(cmd, "usermsg") == 0)
00208 {
00209
00210 if (argc < 2)
00211 errorMissingArgument(argv[0]);
00212 argEaten = argc;
00213 uint16 type = atoi(argv[1]);
00214 uint16 length = argc-2;
00215
00216 UserMessage::DataVector data(length);
00217 for (size_t i = 0; i < length; i++)
00218 data[i] = atoi(argv[i+2]);
00219
00220 UserMessage message(type, data);
00221 message.serialize(stream);
00222 stream->flush();
00223 }
00224 else if (strcmp(cmd, "rdpage") == 0)
00225 {
00226
00227 if (argc < 3)
00228 errorMissingArgument(argv[0]);
00229 argEaten = 2;
00230
00231 CmdBootloaderInterface bootloader(stream, atoi(argv[1]));
00232
00233 vector<uint8> data(bootloader.getPageSize());
00234 if (bootloader.readPage(atoi(argv[2]), &data[0]))
00235 {
00236 ofstream file("page.bin");
00237 if (file.good())
00238 copy(data.begin(), data.end(), ostream_iterator<uint8>(file));
00239 else
00240 errorOpenFile("page.bin");
00241 }
00242 else
00243 errorReadPage(atoi(argv[2]));
00244 }
00245 else if(strcmp(cmd, "rdpageusb") == 0)
00246 {
00247 if (argc < 3)
00248 errorMissingArgument(argv[0]);
00249 argEaten = 2;
00250
00251 CmdBootloaderInterface bootloader(stream, atoi(argv[1]));
00252 vector <uint8> data(2048);
00253 cout << "Page: " << atoi(argv[2]) << endl;
00254 if(bootloader.readPageSimple(atoi(argv[2]), &data[0])) {
00255 ofstream file("page.bin");
00256 if(file.good())
00257 copy(data.begin(),data.end(),ostream_iterator<uint8>(file));
00258 else
00259 errorOpenFile("page.bin");
00260 }
00261 else
00262 errorReadPage(atoi(argv[2]));
00263 }
00264 else if (strcmp(cmd, "whex") == 0)
00265 {
00266 bool reset = 0;
00267
00268 if (argc < 3)
00269 errorMissingArgument(argv[0]);
00270 argEaten = 2;
00271
00272 if (argc > 3 && !strcmp(argv[3], "reset"))
00273 {
00274 reset = 1;
00275 argEaten = 3;
00276 }
00277
00278
00279 try
00280 {
00281 CmdBootloaderInterface bootloader(stream, atoi(argv[1]));
00282 bootloader.writeHex(argv[2], reset, false);
00283 }
00284 catch (HexFile::Error &e)
00285 {
00286 errorHexFile(e.toString());
00287 }
00288 }
00289 else if (strcmp(cmd,"wusb") == 0)
00290 {
00291 bool reset = 0;
00292 if (argc < 3)
00293 errorMissingArgument(argv[0]);
00294 argEaten = 2;
00295 if(argc > 3 && !strcmp(argv[3], "reset"))
00296 {
00297 reset = 1;
00298 argEaten = 3;
00299 }
00300 try
00301 {
00302 CmdBootloaderInterface bootloader(stream, atoi(argv[1]));
00303 bootloader.writeHex(argv[2], reset, true);
00304 }
00305 catch (HexFile::Error &e)
00306 {
00307 errorHexFile(e.toString());
00308 }
00309 }
00310 else if (strcmp(cmd, "rhex") == 0)
00311 {
00312
00313 if (argc < 3)
00314 errorMissingArgument(argv[0]);
00315 argEaten = 2;
00316
00317
00318 try
00319 {
00320 CmdBootloaderInterface bootloader(stream, atoi(argv[1]));
00321 bootloader.readHex(argv[2]);
00322 }
00323 catch (HexFile::Error &e)
00324 {
00325 errorHexFile(e.toString());
00326 }
00327 }
00328 else if (strcmp(cmd, "eb") == 0)
00329 {
00330 uint16 dest;
00331
00332 if(argc < 2)
00333 errorMissingArgument(argv[0]);
00334 argEaten = 1;
00335
00336 dest = atoi(argv[1]);
00337
00338 BootloaderReset msg(dest);
00339 msg.serialize(stream);
00340 stream->flush();
00341
00342
00343
00344
00345 while (true)
00346 {
00347 Message *message = Message::receive(stream);
00348
00349
00350 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message);
00351 if (ackMessage && (ackMessage->source == dest))
00352 {
00353 cout << "Device is now in user-code" << endl;
00354 delete message;
00355 break;
00356 }
00357
00358
00359
00360 delete message;
00361 }
00362 }
00363 else if (strcmp(cmd, "sb") == 0)
00364 {
00365 uint16 dest;
00366
00367 if(argc < 2)
00368 errorMissingArgument(argv[0]);
00369 argEaten = 1;
00370
00371 dest = atoi(argv[1]);
00372
00373 Reboot msg(dest);
00374 msg.serialize(stream);
00375 stream->flush();
00376 }
00377 else if (strcmp(cmd, "sleep") == 0)
00378 {
00379 uint16 dest;
00380 if(argc < 2)
00381 errorMissingArgument(argv[0]);
00382 argEaten = 1;
00383
00384 dest = atoi(argv[1]);
00385
00386 Sleep msg(dest);
00387 msg.serialize(stream);
00388 stream->flush();
00389 } else
00390 errorUnknownCommand(cmd);
00391
00392 return argEaten;
00393 }
00394 }
00395
00396 int main(int argc, char *argv[])
00397 {
00398 Dashel::initPlugins();
00399
00400 const char *target = ASEBA_DEFAULT_TARGET;
00401 int argCounter = 1;
00402
00403 if (argc == 1)
00404 {
00405 Aseba::dumpHelp(std::cout, argv[0]);
00406 return 0;
00407 }
00408
00409 while (argCounter < argc)
00410 {
00411 const char *arg = argv[argCounter];
00412 if (strcmp(arg, "-t") == 0)
00413 {
00414 if (++argCounter < argc)
00415 target = argv[argCounter];
00416 else
00417 Aseba::errorMissingArgument(argv[0]);
00418 }
00419 else if ((strcmp(arg, "-h") == 0) || (strcmp(arg, "--help") == 0))
00420 {
00421 Aseba::dumpHelp(std::cout, argv[0]);
00422 return 0;
00423 }
00424 else if ((strcmp(arg, "-V") == 0) || (strcmp(arg, "--version") == 0))
00425 {
00426 Aseba::dumpVersion(std::cout);
00427 return 0;
00428 }
00429 else
00430 {
00431 Dashel::Hub client;
00432 Dashel::Stream* stream = client.connect(target);
00433 assert(stream);
00434
00435
00436 try
00437 {
00438 argCounter += Aseba::processCommand(stream, argc - argCounter, &argv[argCounter]);
00439 stream->flush();
00440 }
00441 catch (Dashel::DashelException e)
00442 {
00443 Aseba::errorServerDisconnected();
00444 }
00445 catch (Aseba::BootloaderInterface::Error e)
00446 {
00447 Aseba::errorBootloader(e.what());
00448 }
00449 }
00450 argCounter++;
00451 }
00452 return 0;
00453 }
00454