$search
00001 /* 00002 Aseba - an event-based framework for distributed robot control 00003 Copyright (C) 2007--2012: 00004 Stephane Magnenat <stephane at magnenat dot net> 00005 (http://stephane.magnenat.net) 00006 and other contributors, see authors.txt for details 00007 00008 This program is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU Lesser General Public License as published 00010 by the Free Software Foundation, version 3 of the License. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. 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 // reporting function 00141 virtual void writePageStart(unsigned pageNumber, const uint8* data, bool simple) 00142 { 00143 cout << "Writing page " << pageNumber << "... "; 00144 cout.flush(); 00145 //cout << "First data: " << hex << (int) data[0] << "," << hex << (int) data[1] << "," << hex << (int) data[2] << endl; 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 // first arg is type, second is length 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 // first arg is dest, second is page number 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 // first arg is dest, second is file name 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 // try to write hex file 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 // first arg is source, second is file name 00313 if (argc < 3) 00314 errorMissingArgument(argv[0]); 00315 argEaten = 2; 00316 00317 // try to read hex file 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 // Wait ack from bootloader (mean we got out of it) 00343 // Or bootloader description (mean we just entered it) 00344 // WRONG; FIXME 00345 while (true) 00346 { 00347 Message *message = Message::receive(stream); 00348 00349 // handle ack 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 //BootloaderDescription * bMessage = dynamic_cast<BootloaderDescription *>(message); 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 // process command 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