Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "BootloaderInterface.h"
00022 #include "../common/consts.h"
00023 #include "../msg/msg.h"
00024 #include "utils.h"
00025 #include "HexFile.h"
00026 #include "FormatableString.h"
00027 #include <dashel/dashel.h>
00028 #include <memory>
00029 #include <unistd.h>
00030
00031 namespace Aseba
00032 {
00033 using namespace Dashel;
00034 using namespace std;
00035
00036 BootloaderInterface::BootloaderInterface(Stream* stream, int dest) :
00037 stream(stream),
00038 dest(dest),
00039 pageSize(0),
00040 pagesStart(0),
00041 pagesCount(0)
00042 {
00043
00044 }
00045
00046 bool BootloaderInterface::readPage(unsigned pageNumber, uint8* data)
00047 {
00048 if ((pageNumber < pagesStart) || (pageNumber >= pagesStart + pagesCount))
00049 {
00050 throw Error(FormatableString("Error, page index %0 out of page range [%1:%2]").arg(pageNumber).arg(pagesStart).arg(pagesStart+pagesCount));
00051 }
00052
00053
00054 BootloaderReadPage message;
00055 message.dest = dest;
00056 message.pageNumber = pageNumber;
00057 message.serialize(stream);
00058 stream->flush();
00059 unsigned dataRead = 0;
00060
00061
00062 while (true)
00063 {
00064 auto_ptr<Message> message(Message::receive(stream));
00065
00066
00067 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message.get());
00068 if (ackMessage && (ackMessage->source == dest))
00069 {
00070 uint16 errorCode = ackMessage->errorCode;
00071 if (errorCode == BootloaderAck::SUCCESS)
00072 {
00073 if (dataRead < pageSize)
00074 cerr << "Warning, got acknowledgement but page not fully read (" << dataRead << "/" << pageSize << ") bytes.\n";
00075 return true;
00076 }
00077 else
00078 return false;
00079 }
00080
00081
00082 BootloaderDataRead *dataMessage = dynamic_cast<BootloaderDataRead *>(message.get());
00083 if (dataMessage && (dataMessage->source == dest))
00084 {
00085 if (dataRead >= pageSize)
00086 cerr << "Warning, reading oversized page (" << dataRead << "/" << pageSize << ") bytes.\n";
00087 copy(dataMessage->data, dataMessage->data + sizeof(dataMessage->data), data);
00088 data += sizeof(dataMessage->data);
00089 dataRead += sizeof(dataMessage->data);
00090 cout << "Page read so far (" << dataRead << "/" << pageSize << ") bytes.\n";
00091 }
00092 }
00093
00094 return true;
00095 }
00096
00097 bool BootloaderInterface::readPageSimple(unsigned pageNumber, uint8 * data)
00098 {
00099 BootloaderReadPage message;
00100 message.dest = dest;
00101 message.pageNumber = pageNumber;
00102 message.serialize(stream);
00103 stream->flush();
00104
00105 stream->read(data, 2048);
00106 return true;
00107 }
00108
00109 bool BootloaderInterface::writePage(unsigned pageNumber, const uint8 *data, bool simple)
00110 {
00111 writePageStart(pageNumber, data, simple);
00112
00113
00114 BootloaderWritePage writePage;
00115 writePage.dest = dest;
00116 writePage.pageNumber = pageNumber;
00117 writePage.serialize(stream);
00118
00119 if (simple)
00120 {
00121
00122 stream->write(data,pageSize);
00123 }
00124 else
00125 {
00126
00127 stream->flush();
00128
00129
00130 while (true)
00131 {
00132 auto_ptr<Message> message(Message::receive(stream));
00133
00134
00135 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message.get());
00136 if (ackMessage && (ackMessage->source == dest))
00137 {
00138 uint16 errorCode = ackMessage->errorCode;
00139 if(errorCode == BootloaderAck::SUCCESS)
00140 break;
00141 else
00142 return false;
00143 }
00144 }
00145
00146
00147 for (unsigned dataWritten = 0; dataWritten < pageSize;)
00148 {
00149 BootloaderPageDataWrite pageData;
00150 pageData.dest = dest;
00151 copy(data + dataWritten, data + dataWritten + sizeof(pageData.data), pageData.data);
00152 pageData.serialize(stream);
00153 dataWritten += sizeof(pageData.data);
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 }
00174
00175 }
00176
00177
00178 stream->flush();
00179
00180 while (true)
00181 {
00182 writePageWaitAck();
00183 auto_ptr<Message> message(Message::receive(stream));
00184
00185
00186 BootloaderAck *ackMessage = dynamic_cast<BootloaderAck *>(message.get());
00187 if (ackMessage && (ackMessage->source == dest))
00188 {
00189 uint16 errorCode = ackMessage->errorCode;
00190 if(errorCode == BootloaderAck::SUCCESS)
00191 {
00192 writePageSuccess();
00193 return true;
00194 }
00195 else
00196 {
00197 writePageFailure();
00198 return false;
00199 }
00200 }
00201 }
00202
00203
00204 return true;
00205 }
00206
00207 void BootloaderInterface::writeHex(const string &fileName, bool reset, bool simple)
00208 {
00209
00210 HexFile hexFile;
00211 hexFile.read(fileName);
00212
00213 writeHexStart(fileName, reset, simple);
00214
00215 if (reset)
00216 {
00217 Reboot msg(dest);
00218 msg.serialize(stream);
00219 stream->flush();
00220
00221 writeHexEnteringBootloader();
00222 }
00223
00224
00225 if (simple)
00226 {
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 usleep(10000);
00240 pageSize = 2048;
00241 }
00242 else
00243 {
00244
00245 while (true)
00246 {
00247 auto_ptr<Message> message(Message::receive(stream));
00248 BootloaderDescription *bDescMessage = dynamic_cast<BootloaderDescription *>(message.get());
00249 if (bDescMessage && (bDescMessage->source == dest))
00250 {
00251 pageSize = bDescMessage->pageSize;
00252 pagesStart = bDescMessage->pagesStart;
00253 pagesCount = bDescMessage->pagesCount;
00254 break;
00255 }
00256 }
00257 }
00258
00259
00260 typedef map<uint32, vector<uint8> > PageMap;
00261 PageMap pageMap;
00262 for (HexFile::ChunkMap::iterator it = hexFile.data.begin(); it != hexFile.data.end(); it ++)
00263 {
00264
00265 unsigned chunkAddress = it->first;
00266
00267 unsigned chunkDataIndex = 0;
00268
00269 unsigned chunkSize = it->second.size();
00270
00271
00272 do
00273 {
00274
00275 unsigned pageIndex = (chunkAddress + chunkDataIndex) / pageSize;
00276
00277 unsigned byteIndex = (chunkAddress + chunkDataIndex) % pageSize;
00278
00279
00280 if (pageMap.find(pageIndex) == pageMap.end())
00281 {
00282
00283 pageMap[pageIndex] = vector<uint8>(pageSize, (uint8)0);
00284 }
00285
00286 unsigned amountToCopy = min(pageSize - byteIndex, chunkSize - chunkDataIndex);
00287 copy(it->second.begin() + chunkDataIndex, it->second.begin() + chunkDataIndex + amountToCopy, pageMap[pageIndex].begin() + byteIndex);
00288
00289
00290 chunkDataIndex += amountToCopy;
00291 }
00292 while (chunkDataIndex < chunkSize);
00293 }
00294
00295 writeHexGotDescription(pageMap.size());
00296
00297 if (simple)
00298 {
00299
00300 for (PageMap::iterator it = pageMap.begin(); it != pageMap.end(); it ++)
00301 {
00302 unsigned pageIndex = it->first;
00303 if (pageIndex != 0)
00304 if (!writePage(pageIndex, &it->second[0], true))
00305 errorWritePageNonFatal(pageIndex);
00306 }
00307
00308 for (PageMap::iterator it = pageMap.begin(); it != pageMap.end(); it ++)
00309 {
00310 unsigned pageIndex = it->first;
00311 if (pageIndex == 0)
00312 if (!writePage(pageIndex, &it->second[0], true))
00313 errorWritePageNonFatal(pageIndex);
00314 }
00315 }
00316 else
00317 {
00318
00319 for (PageMap::iterator it = pageMap.begin(); it != pageMap.end(); it ++)
00320 {
00321 unsigned pageIndex = it->first;
00322 if ((pageIndex >= pagesStart) && (pageIndex < pagesStart + pagesCount))
00323 if (!writePage(pageIndex, &it->second[0], false))
00324 throw Error(FormatableString("Error while writing page %0").arg(pageIndex));
00325 }
00326 }
00327
00328 writeHexWritten();
00329
00330 if (reset)
00331 {
00332 BootloaderReset msg(dest);
00333 msg.serialize(stream);
00334 stream->flush();
00335
00336 writeHexExitingBootloader();
00337 }
00338 }
00339
00340 void BootloaderInterface::readHex(const string &fileName)
00341 {
00342 HexFile hexFile;
00343
00344
00345 unsigned address = pagesStart * pageSize;
00346 hexFile.data[address] = vector<uint8>();
00347 hexFile.data[address].reserve(pagesCount * pageSize);
00348
00349
00350 for (unsigned page = pagesStart; page < pagesCount; page++)
00351 {
00352 vector<uint8> buffer((uint8)0, pageSize);
00353
00354 if (!readPage(page, &buffer[0]))
00355 throw Error(FormatableString("Error, cannot read page %0").arg(page));
00356
00357 copy(&buffer[0], &buffer[pageSize], back_inserter(hexFile.data[address]));
00358 }
00359
00360
00361 hexFile.strip(pageSize);
00362 hexFile.write(fileName);
00363 }
00364
00365 }