Crazyflie.cpp
Go to the documentation of this file.
00001 //#include <regex>
00002 #include <mutex>
00003 
00004 #include "Crazyflie.h"
00005 #include "crtp.h"
00006 #include "crtpBootloader.h"
00007 #include "crtpNRF51.h"
00008 
00009 #include "Crazyradio.h"
00010 #include "CrazyflieUSB.h"
00011 
00012 #include <fstream>
00013 #include <cstring>
00014 #include <stdexcept>
00015 #include <thread>
00016 #include <cmath>
00017 #include <inttypes.h>
00018 
00019 const static int MAX_RADIOS = 16;
00020 const static int MAX_USB = 4;
00021 const static bool LOG_COMMUNICATION = 0;
00022 
00023 Crazyradio* g_crazyradios[MAX_RADIOS];
00024 std::mutex g_radioMutex[MAX_RADIOS];
00025 
00026 CrazyflieUSB* g_crazyflieUSB[MAX_USB];
00027 std::mutex g_crazyflieusbMutex[MAX_USB];
00028 
00029 Logger EmptyLogger;
00030 
00031 
00032 Crazyflie::Crazyflie(
00033   const std::string& link_uri,
00034   Logger& logger,
00035   std::function<void(const char*)> consoleCb)
00036   : m_radio(nullptr)
00037   , m_transport(nullptr)
00038   , m_devId(0)
00039   , m_channel(0)
00040   , m_address(0)
00041   , m_datarate(Crazyradio::Datarate_250KPS)
00042   , m_logTocEntries()
00043   , m_logBlockCb()
00044   , m_paramTocEntries()
00045   , m_paramValues()
00046   , m_emptyAckCallback(nullptr)
00047   , m_linkQualityCallback(nullptr)
00048   , m_consoleCallback(consoleCb)
00049   , m_log_use_V2(false)
00050   , m_param_use_V2(false)
00051   , m_logger(logger)
00052 {
00053   int datarate;
00054   int channel;
00055   char datarateType;
00056   bool success = false;
00057 
00058   success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c/%" SCNx64,
00059      &m_devId, &channel, &datarate,
00060      &datarateType, &m_address) == 5;
00061   if (!success) {
00062     success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c",
00063        &m_devId, &channel, &datarate,
00064        &datarateType) == 4;
00065     m_address = 0xE7E7E7E7E7;
00066   }
00067 
00068   if (success)
00069   {
00070     m_channel = channel;
00071     if (datarate == 250 && datarateType == 'K') {
00072       m_datarate = Crazyradio::Datarate_250KPS;
00073     }
00074     else if (datarate == 1 && datarateType == 'M') {
00075       m_datarate = Crazyradio::Datarate_1MPS;
00076     }
00077     else if (datarate == 2 && datarateType == 'M') {
00078       m_datarate = Crazyradio::Datarate_2MPS;
00079     }
00080 
00081     if (m_devId >= MAX_RADIOS) {
00082       throw std::runtime_error("This version does not support that many radios. Adjust MAX_RADIOS and recompile!");
00083     }
00084 
00085     {
00086       std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
00087       if (!g_crazyradios[m_devId]) {
00088         g_crazyradios[m_devId] = new Crazyradio(m_devId);
00089         g_crazyradios[m_devId]->enableLogging(LOG_COMMUNICATION);
00090         // g_crazyradios[m_devId]->setAckEnable(false);
00091         g_crazyradios[m_devId]->setAckEnable(true);
00092         g_crazyradios[m_devId]->setArc(0);
00093       }
00094     }
00095 
00096     m_radio = g_crazyradios[m_devId];
00097   }
00098   else {
00099     success = std::sscanf(link_uri.c_str(), "usb://%d",
00100        &m_devId) == 1;
00101 
00102     if (m_devId >= MAX_USB) {
00103       throw std::runtime_error("This version does not support that many CFs over USB. Adjust MAX_USB and recompile!");
00104     }
00105 
00106     {
00107       std::unique_lock<std::mutex> mlock(g_crazyflieusbMutex[m_devId]);
00108       if (!g_crazyflieUSB[m_devId]) {
00109         g_crazyflieUSB[m_devId] = new CrazyflieUSB(m_devId);
00110         g_crazyflieUSB[m_devId]->enableLogging(LOG_COMMUNICATION);
00111       }
00112     }
00113 
00114     m_transport = g_crazyflieUSB[m_devId];
00115   }
00116 
00117   if (!success) {
00118     throw std::runtime_error("Uri is not valid!");
00119   }
00120 
00121   // enable safelink
00122   if (m_radio) {
00123     crtpNrf51SetSafelinkRequest request(ENABLE_SAFELINK);
00124     sendPacketOrTimeout(request, /*useSafeLink*/false);
00125   }
00126 
00127   m_curr_up = 0;
00128   m_curr_down = 0;
00129 
00130   m_protocolVersion = getProtocolVersion();
00131 
00132 }
00133 
00134 int Crazyflie::getProtocolVersion()
00135 {
00136   crtpGetProtocolVersionRequest req;
00137   startBatchRequest();
00138   addRequest(req, 1);
00139   handleRequests();
00140   return getRequestResult<crtpGetProtocolVersionResponse>(0)->version;
00141 }
00142 
00143 std::string Crazyflie::getFirmwareVersion()
00144 {
00145   crtpGetFirmwareVersionRequest req;
00146   startBatchRequest();
00147   addRequest(req, 1);
00148   handleRequests();
00149   return std::string(getRequestResult<crtpGetFirmwareVersionResponse>(0)->version);
00150 }
00151 
00152 std::string Crazyflie::getDeviceTypeName()
00153 {
00154   crtpGetDeviceTypeNameRequest req;
00155   startBatchRequest();
00156   addRequest(req, 1);
00157   handleRequests();
00158   return std::string(getRequestResult<crtpGetDeviceTypeNameResponse>(0)->name);
00159 }
00160 
00161 void Crazyflie::logReset()
00162 {
00163   crtpLogResetRequest request;
00164   startBatchRequest();
00165   addRequest(request, 1);
00166   handleRequests();
00167 }
00168 
00169 void Crazyflie::sendSetpoint(
00170   float roll,
00171   float pitch,
00172   float yawrate,
00173   uint16_t thrust)
00174 {
00175   crtpSetpointRequest request(roll, pitch, yawrate, thrust);
00176   sendPacket((const uint8_t*)&request, sizeof(request));
00177 }
00178 
00179 void Crazyflie::sendStop()
00180 {
00181   crtpStopRequest request;
00182   sendPacket((const uint8_t*)&request, sizeof(request));
00183 }
00184 
00185 void Crazyflie::sendPositionSetpoint(
00186   float x,
00187   float y,
00188   float z,
00189   float yaw)
00190 {
00191   crtpPositionSetpointRequest request(x, y, z, yaw);
00192   sendPacket((const uint8_t*)&request, sizeof(request));
00193 }
00194 
00195 void Crazyflie::sendHoverSetpoint(
00196   float vx,
00197   float vy,
00198   float yawrate,
00199   float zDistance)
00200 {
00201   crtpHoverSetpointRequest request(vx, vy, yawrate, zDistance);
00202   sendPacket((const uint8_t*)&request, sizeof(request));
00203 }
00204 
00205 void Crazyflie::sendFullStateSetpoint(
00206     float x, float y, float z,
00207     float vx, float vy, float vz,
00208     float ax, float ay, float az,
00209     float qx, float qy, float qz, float qw,
00210     float rollRate, float pitchRate, float yawRate)
00211 {
00212   crtpFullStateSetpointRequest request(
00213     x, y, z,
00214     vx, vy, vz,
00215     ax, ay, az,
00216     qx, qy, qz, qw,
00217     rollRate, pitchRate, yawRate);
00218   sendPacket((const uint8_t*)&request, sizeof(request));
00219 }
00220 
00221 void Crazyflie::sendExternalPositionUpdate(
00222   float x,
00223   float y,
00224   float z)
00225 {
00226   crtpExternalPositionUpdate position(x, y, z);
00227   sendPacket((const uint8_t*)&position, sizeof(position));
00228 }
00229 
00230 void Crazyflie::sendPing()
00231 {
00232   uint8_t ping = 0xFF;
00233   sendPacket(&ping, sizeof(ping));
00234 }
00235 
00239 void Crazyflie::transmitPackets()
00240 {
00241   if (!m_outgoing_packets.empty())
00242   {
00243     std::vector<crtpPacket_t>::iterator it;
00244     for (it = m_outgoing_packets.begin(); it != m_outgoing_packets.end(); it++)
00245     {
00246       sendPacket(it->raw, it->size+1);
00247     }
00248     m_outgoing_packets.clear();
00249   }
00250 }
00251 
00252 // https://forum.bitcraze.io/viewtopic.php?f=9&t=1488
00253 void Crazyflie::reboot()
00254 {
00255   if (m_radio) {
00256     crtpNrf51ResetInitRequest req1;
00257     sendPacketOrTimeout(req1);
00258 
00259     crtpNrf51ResetRequest req2(/*bootToFirmware*/ 1);
00260     sendPacketOrTimeout(req2);
00261   }
00262 }
00263 
00264 uint64_t Crazyflie::rebootToBootloader()
00265 {
00266   if (m_radio) {
00267     crtpNrf51ResetInitRequest req;
00268     startBatchRequest();
00269     addRequest(req, 2);
00270     handleRequests();
00271     const crtpNrf51ResetInitResponse* response = getRequestResult<crtpNrf51ResetInitResponse>(0);
00272 
00273     uint64_t result =
00274         ((uint64_t)response->addr[0] << 0)
00275       | ((uint64_t)response->addr[1] << 8)
00276       | ((uint64_t)response->addr[2] << 16)
00277       | ((uint64_t)response->addr[3] << 24)
00278       | ((uint64_t)0xb1 << 32);
00279 
00280     crtpNrf51ResetRequest req2(/*bootToFirmware*/ 0);
00281     sendPacketOrTimeout(req2);
00282 
00283     // switch to new address
00284     m_address = result;
00285     m_channel = 0;
00286     m_datarate = Crazyradio::Datarate_2MPS;
00287 
00288 
00289     return result;
00290   } else {
00291     return -1;
00292   }
00293 }
00294 
00295 void Crazyflie::rebootFromBootloader()
00296 {
00297   if (m_radio) {
00298     bootloaderResetRequest req(/*bootToFirmware*/ 1);
00299     sendPacketOrTimeout(req, /*useSafeLink*/ false);
00300   }
00301 }
00302 
00303 void Crazyflie::sysoff()
00304 {
00305   if (m_radio) {
00306     crtpNrf51SysOffRequest req;
00307     sendPacketOrTimeout(req);
00308   }
00309 }
00310 
00311 void Crazyflie::alloff()
00312 {
00313   if (m_radio) {
00314     crtpNrf51AllOffRequest req;
00315     sendPacketOrTimeout(req);
00316   }
00317 }
00318 
00319 void Crazyflie::syson()
00320 {
00321   if (m_radio) {
00322     crtpNrf51SysOnRequest req;
00323     sendPacketOrTimeout(req);
00324   }
00325 }
00326 
00327 float Crazyflie::vbat()
00328 {
00329   if (m_radio) {
00330     crtpNrf51GetVBatRequest req;
00331     startBatchRequest();
00332     addRequest(req, 2);
00333     handleRequests();
00334     return getRequestResult<crtpNrf51GetVBatResponse>(0)->vbat;
00335   } else {
00336     return nan("");
00337   }
00338 }
00339 
00340 void Crazyflie::writeFlash(
00341   BootloaderTarget target,
00342   const std::vector<uint8_t>& data)
00343 {
00344   // Get info about the target
00345   bootloaderGetInfoRequest req(target);
00346   startBatchRequest();
00347   addRequest(req, 3);
00348   handleRequests(/*crtpMode=*/false, /*useSafeLink*/ false);
00349   const bootloaderGetInfoResponse* response = getRequestResult<bootloaderGetInfoResponse>(0);
00350   uint16_t pageSize = response->pageSize;
00351   uint16_t flashStart = response->flashStart;
00352   uint16_t nBuffPage = response->nBuffPage;
00353 
00354   uint16_t numPages = ceil(data.size() / (float)pageSize);
00355   if (numPages + flashStart >= response->nFlashPage) {
00356     std::stringstream sstr;
00357     sstr << "Requested size too large!";
00358     throw std::runtime_error(sstr.str());
00359   }
00360 
00361   std::stringstream sstr;
00362   sstr << "pageSize: " << pageSize
00363             << " nBuffPage: " << nBuffPage
00364             << " nFlashPage: " << response->nFlashPage
00365             << " flashStart: " << flashStart
00366             << " version: " << (int)response->version
00367             << " numPages: " << numPages;
00368   m_logger.info(sstr.str());
00369 
00370   // write flash
00371   size_t offset = 0;
00372   uint16_t usedBuffers = 0;
00373   // startBatchRequest();
00374   for (uint16_t page = flashStart; page < numPages + flashStart; ++page) {
00375     std::stringstream sstr;
00376     sstr << "page: " << page - flashStart + 1 << " / " << numPages;
00377     m_logger.info(sstr.str());
00378     for (uint16_t address = 0; address < pageSize; address += 25) {
00379 
00380       // std::cout << "request: " << page << " " << address << std::endl;
00381       bootloaderLoadBufferRequest req(target, usedBuffers, address);
00382       size_t requestedSize = std::min<size_t>(data.size() - offset, std::min<size_t>(25, pageSize - address));
00383       memcpy(req.data, &data[offset], requestedSize);
00384       // addRequest(req, 0);
00385       // for (size_t i = 0; i < 10; ++i)
00386       // std::cout << "request: " << req.page << " " << req.address << " " << requestedSize << std::endl;
00387       // for (size_t i = 0; i < 10; ++i) {
00388 
00389       // auto start = std::chrono::system_clock::now();
00390       // while (true) {
00391         sendPacketOrTimeout((uint8_t*)&req, 7 + requestedSize, false);
00392       //   startBatchRequest();
00393       //   bootloaderReadBufferRequest req2(target, usedBuffers, address);
00394       //   addRequest(req2, 7);
00395       //   handleRequests(/*crtpMode=*/false);
00396       //   const bootloaderReadBufferResponse* response = getRequestResult<bootloaderReadBufferResponse>(0);
00397       //   if (memcmp(req.data, response->data, requestedSize) == 0) {
00398       //     break;
00399       //   }
00400       //   auto end = std::chrono::system_clock::now();
00401       //   std::chrono::duration<double> elapsedSeconds = end-start;
00402       //   if (elapsedSeconds.count() > 1.0) {
00403       //     throw std::runtime_error("timeout");
00404       //   }
00405       // }
00406       offset += requestedSize;
00407       if (offset >= data.size()) {
00408         break;
00409       }
00410     }
00411     ++usedBuffers;
00412     if (usedBuffers == nBuffPage
00413         || page == numPages + flashStart - 1) {
00414 
00415 
00416       // startBatchRequest();
00417       // for (uint16_t buf = 0; buf < usedBuffers; ++buf) {
00418       //   for (uint16_t address = 0; address < pageSize; address += 25) {
00419       //     // std::cout << "request: " << page << " " << address << std::endl;
00420       //     bootloaderReadBufferRequest req(target, buf, address);
00421       //     addRequest(req, 7);
00422       //   }
00423       // }
00424       // handleRequests(/*crtpMode=*/false);
00425 
00426 
00427       // upload all the buffers now
00428       // std::cout << "try to upload buffers!" << std::endl;
00429       // handleRequests(/*crtpMode=*/false);
00430       // std::cout << "buffers uploaded!" << std::endl;
00431 
00432       // std::this_thread::sleep_for(std::chrono::milliseconds(100));
00433 
00434       // write flash
00435       bootloaderWriteFlashRequest req(target, 0, page - usedBuffers + 1, usedBuffers);
00436       sendPacketOrTimeout((uint8_t*)&req, sizeof(req), false);
00437 
00438       auto start = std::chrono::system_clock::now();
00439 
00440       size_t tries = 0;
00441       while (true) {
00442         ITransport::Ack ack;
00443         bootloaderFlashStatusRequest statReq(target);
00444         sendPacket((const uint8_t*)&statReq, sizeof(statReq), ack, false);
00445         if (   ack.ack
00446             && ack.size == 5
00447             && memcmp(&req, ack.data, 3) == 0) {
00448           if (ack.data[3] != 1 || ack.data[4] != 0) {
00449             throw std::runtime_error("Error during flashing!");
00450           }
00451           break;
00452         }
00453 
00454         // std::cout << page - usedBuffers + 1 << "," << usedBuffers << std::endl;
00455         // startBatchRequest();
00456         // bootloaderWriteFlashRequest req(target, 0, page - usedBuffers + 1, usedBuffers);
00457         // addRequest(req, 3);
00458         // handleRequests(/*crtpMode=*/false);
00459         // const bootloaderWriteFlashResponse* response = getRequestResult<bootloaderWriteFlashResponse>(0);
00460         // if (response->done == 1 && response->error == 0) {
00461         //   break;
00462         // }
00463         auto end = std::chrono::system_clock::now();
00464         std::chrono::duration<double> elapsedSeconds = end-start;
00465         if (elapsedSeconds.count() > 0.5) {
00466           start = end;
00467           sendPacketOrTimeout((uint8_t*)&req, sizeof(req), false);
00468           ++tries;
00469           if (tries > 5) {
00470             throw std::runtime_error("timeout");
00471           }
00472         }
00473       }
00474 
00475       // std::cout << "Flashed: " << (page - flashStart) / (float)numPages * 100.0 << " %" << std::endl;
00476 
00477       // get ready to fill more buffers
00478       // if (page != numPages + flashStart - 1) {
00479       //   startBatchRequest();
00480       // }
00481       usedBuffers = 0;
00482     }
00483   }
00484 
00485 
00486 }
00487 
00488 void Crazyflie::readFlash(
00489   BootloaderTarget target,
00490   size_t size,
00491   std::vector<uint8_t>& data)
00492 {
00493   // Get info about the target
00494   bootloaderGetInfoRequest req(target);
00495   startBatchRequest();
00496   addRequest(req, 3);
00497   handleRequests(/*crtpMode=*/false, /*useSafelink*/false);
00498   const bootloaderGetInfoResponse* response = getRequestResult<bootloaderGetInfoResponse>(0);
00499   uint16_t pageSize = response->pageSize;
00500   uint16_t flashStart = response->flashStart;
00501 
00502   uint16_t numPages = ceil(size / (float)pageSize);
00503   if (numPages + flashStart >= response->nFlashPage) {
00504     std::stringstream sstr;
00505     sstr << "Requested size too large!";
00506     throw std::runtime_error(sstr.str());
00507   }
00508 
00509   std::stringstream sstr;
00510   sstr << "pageSize: " << pageSize
00511        << " nFlashPage: " << response->nFlashPage
00512        << " flashStart: " << flashStart
00513        << " version: " << (int)response->version
00514        << " numPages: " << numPages;
00515   m_logger.info(sstr.str());
00516 
00517   // read flash
00518   size_t offset = 0;
00519   startBatchRequest();
00520   for (uint16_t page = flashStart; page < numPages + flashStart; ++page) {
00521     for (uint16_t address = 0; address < pageSize; address += 25) {
00522       // std::cout << "request: " << page << " " << address << std::endl;
00523       bootloaderReadFlashRequest req(target, page, address);
00524       addRequest(req, 7);
00525       size_t requestedSize = std::min(25, pageSize - address);
00526       offset += requestedSize;
00527       if (offset > size) {
00528         break;
00529       }
00530     }
00531   }
00532   handleRequests(/*crtpMode=*/false, /*useSafelink*/false);
00533 
00534   // update output
00535   data.resize(size);
00536   size_t i = 0;
00537   offset = 0;
00538   for (uint16_t page = flashStart; page < numPages + flashStart; ++page) {
00539     for (uint16_t address = 0; address < pageSize; address += 25) {
00540       const bootloaderReadFlashResponse* response = getRequestResult<bootloaderReadFlashResponse>(i++);
00541       size_t requestedSize = std::min(25, pageSize - address);
00542       // std::cout << "offset: " << offset << " reqS: " << requestedSize;
00543       memcpy(&data[offset], response->data, std::min(size - offset, requestedSize));
00544       offset += requestedSize;
00545       if (offset > size) {
00546         break;
00547       }
00548     }
00549   }
00550 }
00551 
00552 void Crazyflie::requestLogToc(bool forceNoCache)
00553 {
00554   m_log_use_V2 = true;
00555   uint16_t len;
00556   uint32_t crc;
00557 
00558   crtpLogGetInfoV2Request infoRequest;
00559   startBatchRequest();
00560   addRequest(infoRequest, 1);
00561   if (m_protocolVersion >= 4) {
00562     handleRequests();
00563     len = getRequestResult<crtpLogGetInfoV2Response>(0)->log_len;
00564     crc = getRequestResult<crtpLogGetInfoV2Response>(0)->log_crc;
00565   } else {
00566     // std::cout << "Fall back to V1 param API" << std::endl;
00567     m_log_use_V2 = false;
00568 
00569     crtpLogGetInfoRequest infoRequest;
00570     startBatchRequest();
00571     addRequest(infoRequest, 1);
00572     handleRequests();
00573     len = getRequestResult<crtpLogGetInfoResponse>(0)->log_len;
00574     crc = getRequestResult<crtpLogGetInfoResponse>(0)->log_crc;
00575     // std::cout << len << std::endl;
00576   }
00577 
00578   // check if it is in the cache
00579   std::string fileName = "log" + std::to_string(crc) + ".csv";
00580   std::ifstream infile(fileName);
00581 
00582   if (forceNoCache || !infile.good()) {
00583     m_logger.info("Log: " + std::to_string(len));
00584 
00585     // Request detailed information
00586     startBatchRequest();
00587     if (m_log_use_V2) {
00588       for (size_t i = 0; i < len; ++i) {
00589         crtpLogGetItemV2Request itemRequest(i);
00590         addRequest(itemRequest, 2);
00591       }
00592     } else {
00593       for (size_t i = 0; i < len; ++i) {
00594         crtpLogGetItemRequest itemRequest(i);
00595         addRequest(itemRequest, 2);
00596       }
00597     }
00598     handleRequests();
00599 
00600     // Update internal structure with obtained data
00601     m_logTocEntries.resize(len);
00602     if (m_log_use_V2) {
00603       for (size_t i = 0; i < len; ++i) {
00604         auto response = getRequestResult<crtpLogGetItemV2Response>(i);
00605         LogTocEntry& entry = m_logTocEntries[i];
00606         entry.id = i;
00607         entry.type = (LogType)response->type;
00608         entry.group = std::string(&response->text[0]);
00609         entry.name = std::string(&response->text[entry.group.size() + 1]);
00610       }
00611     } else {
00612       for (size_t i = 0; i < len; ++i) {
00613         auto response = getRequestResult<crtpLogGetItemResponse>(i);
00614         LogTocEntry& entry = m_logTocEntries[i];
00615         entry.id = i;
00616         entry.type = (LogType)response->type;
00617         entry.group = std::string(&response->text[0]);
00618         entry.name = std::string(&response->text[entry.group.size() + 1]);
00619       }
00620     }
00621 
00622     // Write a cache file
00623     {
00624       // Atomic file write: write in temporary file first to avoid race conditions
00625       std::string fileNameTemp = fileName + ".tmp";
00626       std::ofstream output(fileNameTemp);
00627       output << "id,type,group,name" << std::endl;
00628       for (const auto& entry : m_logTocEntries) {
00629         output << std::to_string(entry.id) << ","
00630                << std::to_string(entry.type) << ","
00631                << entry.group << ","
00632                << entry.name << std::endl;
00633       }
00634       // change the filename
00635       rename(fileNameTemp.c_str(), fileName.c_str());
00636     }
00637   } else {
00638     m_logger.info("Found variables in cache.");
00639     m_logTocEntries.clear();
00640     std::string line, cell;
00641     std::getline(infile, line); // ignore header
00642     while (std::getline(infile, line)) {
00643       std::stringstream lineStream(line);
00644       m_logTocEntries.resize(m_logTocEntries.size() + 1);
00645       std::getline(lineStream, cell, ',');
00646       m_logTocEntries.back().id = std::stoi(cell);
00647       std::getline(lineStream, cell, ',');
00648       m_logTocEntries.back().type = (LogType)std::stoi(cell);
00649       std::getline(lineStream, cell, ',');
00650       m_logTocEntries.back().group = cell;
00651       std::getline(lineStream, cell, ',');
00652       m_logTocEntries.back().name = cell;
00653     }
00654   }
00655 }
00656 
00657 void Crazyflie::requestParamToc(bool forceNoCache)
00658 {
00659   m_param_use_V2 = true;
00660   uint16_t numParam;
00661   uint32_t crc;
00662   // Find the number of parameters in TOC
00663   crtpParamTocGetInfoV2Request infoRequest;
00664   startBatchRequest();
00665   // std::cout << "infoReq" << std::endl;
00666   addRequest(infoRequest, 1);
00667   if (m_protocolVersion >= 4) {
00668     handleRequests();
00669     numParam = getRequestResult<crtpParamTocGetInfoV2Response>(0)->numParam;
00670     crc = getRequestResult<crtpParamTocGetInfoV2Response>(0)->crc;
00671   } else {
00672     // std::cout << "Fall back to V1 param API" << std::endl;
00673     m_param_use_V2 = false;
00674 
00675     crtpParamTocGetInfoRequest infoRequest;
00676     startBatchRequest();
00677     addRequest(infoRequest, 1);
00678     handleRequests();
00679     numParam = getRequestResult<crtpParamTocGetInfoResponse>(0)->numParam;
00680     crc = getRequestResult<crtpParamTocGetInfoResponse>(0)->crc;
00681   }
00682 
00683   // check if it is in the cache
00684   std::string fileName = "params" + std::to_string(crc) + ".csv";
00685   std::ifstream infile(fileName);
00686 
00687   if (forceNoCache || !infile.good()) {
00688     m_logger.info("Params: " + std::to_string(numParam));
00689 
00690     // Request detailed information and values
00691     startBatchRequest();
00692     if (!m_param_use_V2) {
00693       for (uint16_t i = 0; i < numParam; ++i) {
00694         crtpParamTocGetItemRequest itemRequest(i);
00695         addRequest(itemRequest, 2);
00696         crtpParamReadRequest readRequest(i);
00697         addRequest(readRequest, 1);
00698       }
00699     } else {
00700       for (uint16_t i = 0; i < numParam; ++i) {
00701         crtpParamTocGetItemV2Request itemRequest(i);
00702         addRequest(itemRequest, 2);
00703         crtpParamReadV2Request readRequest(i);
00704         addRequest(readRequest, 1);
00705       }
00706     }
00707     handleRequests();
00708     // Update internal structure with obtained data
00709     m_paramTocEntries.resize(numParam);
00710 
00711     if (!m_param_use_V2) {
00712       for (uint16_t i = 0; i < numParam; ++i) {
00713         auto r = getRequestResult<crtpParamTocGetItemResponse>(i*2+0);
00714         auto val = getRequestResult<crtpParamValueResponse>(i*2+1);
00715 
00716         ParamTocEntry& entry = m_paramTocEntries[i];
00717         entry.id = i;
00718         entry.type = (ParamType)(r->length | r-> type << 2 | r->sign << 3);
00719         entry.readonly = r->readonly;
00720         entry.group = std::string(&r->text[0]);
00721         entry.name = std::string(&r->text[entry.group.size() + 1]);
00722 
00723         ParamValue v;
00724         std::memcpy(&v, &val->valueFloat, 4);
00725         m_paramValues[i] = v;
00726       }
00727     } else {
00728       for (uint16_t i = 0; i < numParam; ++i) {
00729         auto r = getRequestResult<crtpParamTocGetItemV2Response>(i*2+0);
00730         auto val = getRequestResult<crtpParamValueV2Response>(i*2+1);
00731 
00732         ParamTocEntry& entry = m_paramTocEntries[i];
00733         entry.id = i;
00734         entry.type = (ParamType)(r->length | r-> type << 2 | r->sign << 3);
00735         entry.readonly = r->readonly;
00736         entry.group = std::string(&r->text[0]);
00737         entry.name = std::string(&r->text[entry.group.size() + 1]);
00738 
00739         ParamValue v;
00740         std::memcpy(&v, &val->valueFloat, 4);
00741         m_paramValues[i] = v;
00742       }
00743     }
00744 
00745     // Write a cache file
00746     {
00747       // Atomic file write: write in temporary file first to avoid race conditions
00748       std::string fileNameTemp = fileName + ".tmp";
00749       std::ofstream output(fileNameTemp);
00750       output << "id,type,readonly,group,name" << std::endl;
00751       for (const auto& entry : m_paramTocEntries) {
00752         output << std::to_string(entry.id) << ","
00753                << std::to_string(entry.type) << ","
00754                << std::to_string(entry.readonly) << ","
00755                << entry.group << ","
00756                << entry.name << std::endl;
00757       }
00758       // change the filename
00759       rename(fileNameTemp.c_str(), fileName.c_str());
00760     }
00761   } else {
00762     m_logger.info("Found variables in cache.");
00763     m_paramTocEntries.clear();
00764     std::string line, cell;
00765     std::getline(infile, line); // ignore header
00766     while (std::getline(infile, line)) {
00767       std::stringstream lineStream(line);
00768       m_paramTocEntries.resize(m_paramTocEntries.size() + 1);
00769       std::getline(lineStream, cell, ',');
00770       m_paramTocEntries.back().id = std::stoi(cell);
00771       std::getline(lineStream, cell, ',');
00772       m_paramTocEntries.back().type = (ParamType)std::stoi(cell);
00773       std::getline(lineStream, cell, ',');
00774       m_paramTocEntries.back().readonly = std::stoi(cell);
00775       std::getline(lineStream, cell, ',');
00776       m_paramTocEntries.back().group = cell;
00777       std::getline(lineStream, cell, ',');
00778       m_paramTocEntries.back().name = cell;
00779     }
00780 
00781     // Request values
00782     if (!m_param_use_V2) {
00783       startBatchRequest();
00784       for (size_t i = 0; i < numParam; ++i) {
00785         crtpParamReadRequest readRequest(i);
00786         addRequest(readRequest, 1);
00787       }
00788       handleRequests();
00789       for (size_t i = 0; i < numParam; ++i) {
00790         auto val = getRequestResult<crtpParamValueResponse>(i);
00791         ParamValue v;
00792         std::memcpy(&v, &val->valueFloat, 4);
00793         m_paramValues[i] = v;
00794       }
00795     } else {
00796       startBatchRequest();
00797       for (size_t i = 0; i < numParam; ++i) {
00798         crtpParamReadV2Request readRequest(i);
00799         addRequest(readRequest, 1);
00800       }
00801       handleRequests();
00802       for (size_t i = 0; i < numParam; ++i) {
00803         auto val = getRequestResult<crtpParamValueV2Response>(i);
00804         ParamValue v;
00805         std::memcpy(&v, &val->valueFloat, 4);
00806         m_paramValues[i] = v;
00807       }
00808     }
00809   }
00810 }
00811 
00812 void Crazyflie::requestMemoryToc()
00813 {
00814   // Find the number of parameters in TOC
00815   crtpMemoryGetNumberRequest infoRequest;
00816   startBatchRequest();
00817   addRequest(infoRequest, 1);
00818   handleRequests();
00819   uint8_t len = getRequestResult<crtpMemoryGetNumberResponse>(0)->numberOfMemories;
00820 
00821   m_logger.info("Memories: " + std::to_string(len));
00822 
00823   // Request detailed information and values
00824   startBatchRequest();
00825   for (uint8_t i = 0; i < len; ++i) {
00826     crtpMemoryGetInfoRequest itemRequest(i);
00827     addRequest(itemRequest, 2);
00828   }
00829   handleRequests();
00830 
00831   // Update internal structure with obtained data
00832   m_memoryTocEntries.resize(len);
00833   for (uint8_t i = 0; i < len; ++i) {
00834     auto info = getRequestResult<crtpMemoryGetInfoResponse>(i);
00835 
00836     MemoryTocEntry& entry = m_memoryTocEntries[i];
00837     entry.id = i;
00838     entry.type = (MemoryType)info->memType;
00839     entry.size = info->memSize;
00840     entry.addr = info->memAddr;
00841   }
00842 }
00843 
00844 void Crazyflie::startSetParamRequest()
00845 {
00846   startBatchRequest();
00847 }
00848 
00849 void Crazyflie::addSetParam(uint8_t id, const ParamValue& value)
00850 {
00851   bool found = false;
00852   for (auto&& entry : m_paramTocEntries) {
00853     if (entry.id == id) {
00854       found = true;
00855       if (!m_param_use_V2) {
00856         switch (entry.type) {
00857           case ParamTypeUint8:
00858             {
00859               crtpParamWriteRequest<uint8_t> request(id, value.valueUint8);
00860               addRequest(request, 1);
00861               break;
00862             }
00863           case ParamTypeInt8:
00864             {
00865               crtpParamWriteRequest<int8_t> request(id, value.valueInt8);
00866               addRequest(request, 1);
00867               break;
00868             }
00869           case ParamTypeUint16:
00870             {
00871               crtpParamWriteRequest<uint16_t> request(id, value.valueUint16);
00872               addRequest(request, 1);
00873               break;
00874             }
00875           case ParamTypeInt16:
00876             {
00877               crtpParamWriteRequest<int16_t> request(id, value.valueInt16);
00878               addRequest(request, 1);
00879               break;
00880             }
00881           case ParamTypeUint32:
00882             {
00883               crtpParamWriteRequest<uint32_t> request(id, value.valueUint32);
00884               addRequest(request, 1);
00885               break;
00886             }
00887           case ParamTypeInt32:
00888             {
00889               crtpParamWriteRequest<int32_t> request(id, value.valueInt32);
00890               addRequest(request, 1);
00891               break;
00892             }
00893           case ParamTypeFloat:
00894             {
00895               crtpParamWriteRequest<float> request(id, value.valueFloat);
00896               addRequest(request, 1);
00897               break;
00898             }
00899         }
00900       } else {
00901         switch (entry.type) {
00902           case ParamTypeUint8:
00903             {
00904               crtpParamWriteV2Request<uint8_t> request(id, value.valueUint8);
00905               addRequest(request, 2);
00906               break;
00907             }
00908           case ParamTypeInt8:
00909             {
00910               crtpParamWriteV2Request<int8_t> request(id, value.valueInt8);
00911               addRequest(request, 2);
00912               break;
00913             }
00914           case ParamTypeUint16:
00915             {
00916               crtpParamWriteV2Request<uint16_t> request(id, value.valueUint16);
00917               addRequest(request, 2);
00918               break;
00919             }
00920           case ParamTypeInt16:
00921             {
00922               crtpParamWriteV2Request<int16_t> request(id, value.valueInt16);
00923               addRequest(request, 2);
00924               break;
00925             }
00926           case ParamTypeUint32:
00927             {
00928               crtpParamWriteV2Request<uint32_t> request(id, value.valueUint32);
00929               addRequest(request, 2);
00930               break;
00931             }
00932           case ParamTypeInt32:
00933             {
00934               crtpParamWriteV2Request<int32_t> request(id, value.valueInt32);
00935               addRequest(request, 2);
00936               break;
00937             }
00938           case ParamTypeFloat:
00939             {
00940               crtpParamWriteV2Request<float> request(id, value.valueFloat);
00941               addRequest(request, 2);
00942               break;
00943             }
00944         }
00945       }
00946     }
00947   }
00948 
00949   if (!found) {
00950     std::stringstream sstr;
00951     sstr << "Could not find parameter with id " << id;
00952     throw std::runtime_error(sstr.str());
00953   }
00954 
00955   m_paramValues[id] = value;
00956 }
00957 
00958 void Crazyflie::setRequestedParams()
00959 {
00960   handleRequests();
00961 }
00962 
00963 void Crazyflie::setParam(uint8_t id, const ParamValue& value)
00964 {
00965   startBatchRequest();
00966   addSetParam(id, value);
00967   setRequestedParams();
00968 }
00969 
00970 bool Crazyflie::sendPacket(
00971   const uint8_t* data,
00972   uint32_t length,
00973   bool useSafeLink)
00974 {
00975   ITransport::Ack ack;
00976   sendPacket(data, length, ack, useSafeLink);
00977   return ack.ack;
00978 }
00979 
00980  void Crazyflie::sendPacketOrTimeout(
00981    const uint8_t* data,
00982    uint32_t length,
00983    bool useSafeLink,
00984    float timeout)
00985 {
00986   auto start = std::chrono::system_clock::now();
00987   while (!sendPacket(data, length, useSafeLink)) {
00988     auto end = std::chrono::system_clock::now();
00989     std::chrono::duration<double> elapsedSeconds = end-start;
00990     if (elapsedSeconds.count() > timeout) {
00991       throw std::runtime_error("timeout");
00992     }
00993   }
00994 }
00995 
00996 void Crazyflie::sendPacket(
00997   const uint8_t* data,
00998   uint32_t length,
00999   ITransport::Ack& ack,
01000   bool useSafeLink)
01001 {
01002   static uint32_t numPackets = 0;
01003   static uint32_t numAcks = 0;
01004 
01005   numPackets++;
01006 
01007   if (m_radio) {
01008     std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01009     if (m_radio->getAddress() != m_address) {
01010       m_radio->setAddress(m_address);
01011     }
01012     if (m_radio->getChannel() != m_channel) {
01013       m_radio->setChannel(m_channel);
01014     }
01015     if (m_radio->getDatarate() != m_datarate) {
01016       m_radio->setDatarate(m_datarate);
01017     }
01018     if (!m_radio->getAckEnable()) {
01019       m_radio->setAckEnable(true);
01020     }
01021     // consider safelink here:
01022     //    Adds 1bit counter to CRTP header to guarantee that no ack (downlink)
01023     //    payload are lost and no uplink packet are duplicated.
01024     //    The caller should resend packet if not acked (ie. same as with a
01025     //    direct call to crazyradio.send_packet)
01026     if (useSafeLink) {
01027       std::vector<uint8_t> dataCopy(data, data + length);
01028       dataCopy[0] &= 0xF3;
01029       dataCopy[0] |= m_curr_up << 3 | m_curr_down << 2;
01030       m_radio->sendPacket(dataCopy.data(), length, ack);
01031       if (ack.ack && ack.size > 0 && (ack.data[0] & 0x04) == (m_curr_down << 2)) {
01032         m_curr_down = 1 - m_curr_down;
01033       }
01034       if (ack.ack) {
01035         m_curr_up = 1 - m_curr_up;
01036       }
01037     } else {
01038       m_radio->sendPacket(data, length, ack);
01039     }
01040 
01041   } else {
01042     std::unique_lock<std::mutex> mlock(g_crazyflieusbMutex[m_devId]);
01043     m_transport->sendPacket(data, length, ack);
01044   }
01045   ack.data[ack.size] = 0;
01046   if (ack.ack) {
01047     handleAck(ack);
01048     numAcks++;
01049   }
01050   if (numPackets == 100) {
01051     if (m_linkQualityCallback) {
01052       // We just take the ratio of sent vs. acked packets here
01053       // for a sliding window of 100 packets
01054       float linkQuality = numAcks / (float)numPackets;
01055       m_linkQualityCallback(linkQuality);
01056     }
01057     numPackets = 0;
01058     numAcks = 0;
01059   }
01060 }
01061 
01062 void Crazyflie::handleAck(
01063   const ITransport::Ack& result)
01064 {
01065   if (crtpConsoleResponse::match(result)) {
01066     if (result.size > 0) {
01067       crtpConsoleResponse* r = (crtpConsoleResponse*)result.data;
01068       if (m_consoleCallback) {
01069         m_consoleCallback(r->text);
01070       }
01071     }
01072     // ROS_INFO("Console: %s", r->text);
01073   }
01074   else if (crtpLogGetInfoResponse::match(result)) {
01075     // handled in batch system
01076   }
01077   else if (crtpLogGetItemResponse::match(result)) {
01078     // handled in batch system
01079   }
01080   else if (crtpLogControlResponse::match(result)) {
01081     // handled in batch system
01082   }
01083   else if (crtpLogDataResponse::match(result)) {
01084     crtpLogDataResponse* r = (crtpLogDataResponse*)result.data;
01085     auto iter = m_logBlockCb.find(r->blockId);
01086     if (iter != m_logBlockCb.end()) {
01087       iter->second(r, result.size - 5);
01088     }
01089     else {
01090       m_logger.warning("Received unrequested data for block: " + std::to_string((int)r->blockId));
01091     }
01092   }
01093   else if (crtpParamTocGetInfoResponse::match(result)) {
01094     // handled in batch system
01095   }
01096   else if (crtpParamTocGetItemResponse::match(result)) {
01097     // handled in batch system
01098   }
01099   else if (crtpParamTocGetInfoV2Response::match(result)) {
01100     // handled in batch system
01101   }
01102   else if (crtpParamTocGetItemV2Response::match(result)) {
01103     // handled in batch system
01104   }
01105   else if (crtpMemoryGetNumberResponse::match(result)) {
01106     // handled in batch system
01107   }
01108   else if (crtpMemoryGetInfoResponse::match(result)) {
01109     // handled in batch system
01110   }
01111   else if (crtpParamValueResponse::match(result)) {
01112     // handled in batch system
01113   }
01114   else if (crtpMemoryGetNumberResponse::match(result)) {
01115     // handled in batch system
01116   }
01117   else if (crtpMemoryReadResponse::match(result)) {
01118     // handled in batch system
01119   }
01120   else if (crtpMemoryWriteResponse::match(result)) {
01121     // handled in batch system
01122   }
01123   else if (crtp(result.data[0]).port == 8) {
01124     // handled in batch system
01125   }
01126   else if (crtpPlatformRSSIAck::match(result)) {
01127     if (result.size >= 3) {
01128       crtpPlatformRSSIAck* r = (crtpPlatformRSSIAck*)result.data;
01129       if (m_emptyAckCallback) {
01130         m_emptyAckCallback(r);
01131       }
01132     }
01133   }
01134   else {
01135     crtp* header = (crtp*)result.data;
01136     m_logger.warning("Don't know ack: Port: " + std::to_string((int)header->port)
01137       + " Channel: " + std::to_string((int)header->channel)
01138       + " Len: " + std::to_string((int)result.size));
01139     // for (size_t i = 1; i < result.size; ++i) {
01140     //   std::cout << "    " << (int)result.data[i] << std::endl;
01141     // }
01142     if (m_genericPacketCallback) {
01143       m_genericPacketCallback(result);
01144     }
01145   }
01146 }
01147 
01148 const Crazyflie::LogTocEntry* Crazyflie::getLogTocEntry(
01149   const std::string& group,
01150   const std::string& name) const
01151 {
01152   for (auto&& entry : m_logTocEntries) {
01153     if (entry.group == group && entry.name == name) {
01154       return &entry;
01155     }
01156   }
01157   return nullptr;
01158 }
01159 
01160 const Crazyflie::ParamTocEntry* Crazyflie::getParamTocEntry(
01161   const std::string& group,
01162   const std::string& name) const
01163 {
01164   for (auto&& entry : m_paramTocEntries) {
01165     if (entry.group == group && entry.name == name) {
01166       return &entry;
01167     }
01168   }
01169   return nullptr;
01170 }
01171 
01172 uint8_t Crazyflie::registerLogBlock(
01173   std::function<void(crtpLogDataResponse*, uint8_t)> cb)
01174 {
01175   for (uint8_t id = 0; id < 255; ++id) {
01176     if (m_logBlockCb.find(id) == m_logBlockCb.end()) {
01177       m_logBlockCb[id] = cb;
01178       return id;
01179     }
01180   }
01181   return 255;
01182 }
01183 
01184 bool Crazyflie::unregisterLogBlock(
01185   uint8_t id)
01186 {
01187   m_logBlockCb.erase(m_logBlockCb.find(id));
01188   return true;
01189 }
01190 
01191 // Batch system
01192 
01193 void Crazyflie::startBatchRequest()
01194 {
01195   m_batchRequests.clear();
01196 }
01197 
01198 void Crazyflie::addRequest(
01199   const uint8_t* data,
01200   size_t numBytes,
01201   size_t numBytesToMatch)
01202 {
01203   m_batchRequests.resize(m_batchRequests.size() + 1);
01204   m_batchRequests.back().request.resize(numBytes);
01205   memcpy(m_batchRequests.back().request.data(), data, numBytes);
01206   m_batchRequests.back().numBytesToMatch = numBytesToMatch;
01207   m_batchRequests.back().finished = false;
01208 }
01209 
01210 void Crazyflie::handleRequests(
01211   bool crtpMode,
01212   bool useSafeLink,
01213   float baseTime,
01214   float timePerRequest)
01215 {
01216   auto start = std::chrono::system_clock::now();
01217   ITransport::Ack ack;
01218   m_numRequestsFinished = 0;
01219   bool sendPing = false;
01220 
01221   float timeout = baseTime + timePerRequest * m_batchRequests.size();
01222 
01223   while (true) {
01224     if (!crtpMode || !sendPing) {
01225       for (const auto& request : m_batchRequests) {
01226         if (!request.finished) {
01227           // std::cout << "sendReq" << std::endl;
01228           sendPacket(request.request.data(), request.request.size(), ack, useSafeLink);
01229           handleBatchAck(ack, crtpMode);
01230 
01231           auto end = std::chrono::system_clock::now();
01232           std::chrono::duration<double> elapsedSeconds = end-start;
01233           if (elapsedSeconds.count() > timeout) {
01234             throw std::runtime_error("timeout");
01235           }
01236         }
01237       }
01238       if (m_radio) {
01239         sendPing = true;
01240       }
01241     } else {
01242       for (size_t i = 0; i < 10; ++i) {
01243         uint8_t ping = 0xFF;
01244         sendPacket(&ping, sizeof(ping), ack, useSafeLink);
01245         handleBatchAck(ack, crtpMode);
01246         // if (ack.ack && crtpPlatformRSSIAck::match(ack)) {
01247         //   sendPing = false;
01248         // }
01249 
01250         auto end = std::chrono::system_clock::now();
01251         std::chrono::duration<double> elapsedSeconds = end-start;
01252         if (elapsedSeconds.count() > timeout) {
01253           throw std::runtime_error("timeout");
01254         }
01255       }
01256 
01257       sendPing = false;
01258     }
01259     if (m_numRequestsFinished == m_batchRequests.size()) {
01260       break;
01261     }
01262   }
01263 }
01264 
01265 void Crazyflie::handleBatchAck(
01266   const ITransport::Ack& ack,
01267   bool crtpMode)
01268 {
01269   if (ack.ack) {
01270     for (auto& request : m_batchRequests) {
01271       if (crtpMode) {
01272         if ((crtp(ack.data[0]) == crtp(request.request[0]) || ack.data[0] == request.request[0])
01273             && memcmp(&ack.data[1], &request.request[1], request.numBytesToMatch) == 0
01274             && !request.finished) {
01275           request.ack = ack;
01276           request.finished = true;
01277           ++m_numRequestsFinished;
01278           // std::cout << "gotack" <<std::endl;
01279           return;
01280         }
01281       } else {
01282         if (!request.finished
01283             && memcmp(&ack.data[0], &request.request[0], request.numBytesToMatch) == 0) {
01284           request.ack = ack;
01285           request.finished = true;
01286           ++m_numRequestsFinished;
01287           // std::cout << m_numRequestsFinished / (float)m_batchRequests.size() * 100.0 << " %" << std::endl;
01288           return;
01289         }
01290       }
01291     }
01292     // ack is (also) handled in sendPacket
01293   }
01294 }
01295 
01296 void Crazyflie::setGroupMask(uint8_t groupMask)
01297 {
01298   crtpCommanderHighLevelSetGroupMaskRequest request(groupMask);
01299   startBatchRequest();
01300   addRequest(request, 2);
01301   handleRequests();
01302 }
01303 
01304 void Crazyflie::takeoff(float height, float duration, uint8_t groupMask)
01305 {
01306   crtpCommanderHighLevelTakeoffRequest req(groupMask, height, duration);
01307   sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01308 }
01309 
01310 void Crazyflie::land(float height, float duration, uint8_t groupMask)
01311 {
01312   crtpCommanderHighLevelLandRequest req(groupMask, height, duration);
01313   sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01314 }
01315 
01316 void Crazyflie::stop(uint8_t groupMask)
01317 {
01318   crtpCommanderHighLevelStopRequest req(groupMask);
01319   sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01320 }
01321 
01322 void Crazyflie::goTo(float x, float y, float z, float yaw, float duration, bool relative, uint8_t groupMask)
01323 {
01324   crtpCommanderHighLevelGoToRequest req(groupMask, relative, x, y, z, yaw, duration);
01325   sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01326 }
01327 
01328 void Crazyflie::uploadTrajectory(
01329   uint8_t trajectoryId,
01330   uint32_t pieceOffset,
01331   const std::vector<poly4d>& pieces)
01332 {
01333   for (const auto& entry : m_memoryTocEntries) {
01334     if (entry.type == MemoryTypeTRAJ) {
01335       startBatchRequest();
01336       // upload pieces
01337       size_t remainingBytes = sizeof(poly4d) * pieces.size();
01338       size_t numRequests = ceil(remainingBytes / 24);
01339       for (size_t i = 0; i < numRequests; ++i) {
01340         crtpMemoryWriteRequest req(entry.id, pieceOffset * sizeof(poly4d) + i*24);
01341         size_t size = std::min<size_t>(remainingBytes, 24);
01342         memcpy(req.data, reinterpret_cast<const uint8_t*>(pieces.data()) + i * 24, size);
01343         remainingBytes -= size;
01344         addRequest(reinterpret_cast<const uint8_t*>(&req), 6 + size, 5);
01345       }
01346       // define trajectory
01347       crtpCommanderHighLevelDefineTrajectoryRequest req(trajectoryId);
01348       req.description.trajectoryLocation = TRAJECTORY_LOCATION_MEM;
01349       req.description.trajectoryType = TRAJECTORY_TYPE_POLY4D;
01350       req.description.trajectoryIdentifier.mem.offset = pieceOffset * sizeof(poly4d);
01351       req.description.trajectoryIdentifier.mem.n_pieces = (uint8_t)pieces.size();
01352       addRequest(req, 2);
01353       handleRequests();
01354       return;
01355     }
01356   }
01357   throw std::runtime_error("Could not find MemoryTypeTRAJ!");
01358 }
01359 
01360 void Crazyflie::startTrajectory(
01361   uint8_t trajectoryId,
01362   float timescale,
01363   bool reversed,
01364   bool relative,
01365   uint8_t groupMask)
01366 {
01367   crtpCommanderHighLevelStartTrajectoryRequest req(groupMask, relative, reversed, trajectoryId, timescale);
01368   sendPacketOrTimeout((uint8_t*)&req, sizeof(req));
01369 }
01370 
01372 
01373 CrazyflieBroadcaster::CrazyflieBroadcaster(
01374   const std::string& link_uri)
01375   : m_radio(nullptr)
01376   , m_devId(0)
01377   , m_channel(0)
01378   , m_address(0)
01379   , m_datarate(Crazyradio::Datarate_250KPS)
01380 {
01381   int datarate;
01382   int channel;
01383   char datarateType;
01384   bool success = false;
01385 
01386   success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c/%" SCNx64,
01387      &m_devId, &channel, &datarate,
01388      &datarateType, &m_address) == 5;
01389   if (!success) {
01390     success = std::sscanf(link_uri.c_str(), "radio://%d/%d/%d%c",
01391        &m_devId, &channel, &datarate,
01392        &datarateType) == 4;
01393     m_address = 0xE7E7E7E7E7;
01394   }
01395 
01396   if (success)
01397   {
01398     m_channel = channel;
01399     if (datarate == 250 && datarateType == 'K') {
01400       m_datarate = Crazyradio::Datarate_250KPS;
01401     }
01402     else if (datarate == 1 && datarateType == 'M') {
01403       m_datarate = Crazyradio::Datarate_1MPS;
01404     }
01405     else if (datarate == 2 && datarateType == 'M') {
01406       m_datarate = Crazyradio::Datarate_2MPS;
01407     }
01408 
01409     if (m_devId >= MAX_RADIOS) {
01410       throw std::runtime_error("This version does not support that many radios. Adjust MAX_RADIOS and recompile!");
01411     }
01412 
01413     {
01414       std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01415       if (!g_crazyradios[m_devId]) {
01416         g_crazyradios[m_devId] = new Crazyradio(m_devId);
01417         g_crazyradios[m_devId]->enableLogging(LOG_COMMUNICATION);
01418         // g_crazyradios[m_devId]->setAckEnable(false);
01419         g_crazyradios[m_devId]->setAckEnable(true);
01420         g_crazyradios[m_devId]->setArc(0);
01421       }
01422     }
01423 
01424     m_radio = g_crazyradios[m_devId];
01425   }
01426   else {
01427     throw std::runtime_error("Uri is not valid!");
01428   }
01429 }
01430 
01431 void CrazyflieBroadcaster::sendPacket(
01432   const uint8_t* data,
01433   uint32_t length)
01434 {
01435   std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01436   if (m_radio->getAddress() != m_address) {
01437     m_radio->setAddress(m_address);
01438   }
01439   if (m_radio->getChannel() != m_channel) {
01440     m_radio->setChannel(m_channel);
01441   }
01442   if (m_radio->getDatarate() != m_datarate) {
01443     m_radio->setDatarate(m_datarate);
01444   }
01445   if (m_radio->getAckEnable()) {
01446     m_radio->setAckEnable(false);
01447   }
01448   m_radio->sendPacketNoAck(data, length);
01449 }
01450 
01451 void CrazyflieBroadcaster::send2Packets(
01452   const uint8_t* data,
01453   uint32_t length)
01454 {
01455   std::unique_lock<std::mutex> mlock(g_radioMutex[m_devId]);
01456   if (m_radio->getAddress() != m_address) {
01457     m_radio->setAddress(m_address);
01458   }
01459   if (m_radio->getChannel() != m_channel) {
01460     m_radio->setChannel(m_channel);
01461   }
01462   if (m_radio->getDatarate() != m_datarate) {
01463     m_radio->setDatarate(m_datarate);
01464   }
01465   if (m_radio->getAckEnable()) {
01466     m_radio->setAckEnable(false);
01467   }
01468   m_radio->send2PacketsNoAck(data, length);
01469 }
01470 
01471 void CrazyflieBroadcaster::takeoff(float height, float duration, uint8_t groupMask)
01472 {
01473   crtpCommanderHighLevelTakeoffRequest req(groupMask, height, duration);
01474   sendPacket((uint8_t*)&req, sizeof(req));
01475 }
01476 
01477 void CrazyflieBroadcaster::land(float height, float duration, uint8_t groupMask)
01478 {
01479   crtpCommanderHighLevelLandRequest req(groupMask, height, duration);
01480   sendPacket((uint8_t*)&req, sizeof(req));
01481 }
01482 
01483 void CrazyflieBroadcaster::stop(uint8_t groupMask)
01484 {
01485   crtpCommanderHighLevelStopRequest req(groupMask);
01486   sendPacket((uint8_t*)&req, sizeof(req));
01487 }
01488 
01489 // This is always in relative coordinates
01490 void CrazyflieBroadcaster::goTo(float x, float y, float z, float yaw, float duration, uint8_t groupMask)
01491 {
01492   crtpCommanderHighLevelGoToRequest req(groupMask, true, x, y, z, yaw, duration);
01493   sendPacket((uint8_t*)&req, sizeof(req));
01494 }
01495 
01496 // This is always in relative coordinates
01497 // TODO: this does not support trajectories that are of a different length!
01498 void CrazyflieBroadcaster::startTrajectory(
01499   uint8_t trajectoryId,
01500   float timescale,
01501   bool reversed,
01502   uint8_t groupMask)
01503 {
01504   crtpCommanderHighLevelStartTrajectoryRequest req(groupMask, true, reversed, trajectoryId, timescale);
01505   sendPacket((uint8_t*)&req, sizeof(req));
01506 }
01507 
01508 void CrazyflieBroadcaster::sendExternalPositions(
01509   const std::vector<externalPosition>& data)
01510 {
01511   if (data.size() == 0) {
01512     return;
01513   }
01514 
01515   std::vector<crtpExternalPositionPacked> requests(ceil(data.size() / 4.0));
01516   for (size_t i = 0; i < data.size(); ++i) {
01517     size_t j = i / 4;
01518     requests[j].positions[i%4].id = data[i].id;
01519     requests[j].positions[i%4].x = data[i].x * 1000;
01520     requests[j].positions[i%4].y = data[i].y * 1000;
01521     requests[j].positions[i%4].z = data[i].z * 1000;
01522   }
01523 
01524   size_t remainingRequests = requests.size();
01525   size_t i = 0;
01526   while (remainingRequests > 0) {
01527     if (remainingRequests >= 2) {
01528       send2Packets(reinterpret_cast<const uint8_t*>(&requests[i]), 2 * sizeof(crtpExternalPositionPacked));
01529       remainingRequests -= 2;
01530       i += 2;
01531     } else {
01532       sendPacket(reinterpret_cast<const uint8_t*>(&requests[i]), sizeof(crtpExternalPositionPacked));
01533       remainingRequests -= 1;
01534       i += 1;
01535     }
01536   }
01537 }
01538 
01539 static float const POSITION_LIMIT = 8.0f; // meters
01540 static const uint32_t INT24_MAX = 8388607;
01541 static inline posFixed24_t position_float_to_fix24(float x)
01542 {
01543   uint32_t val = (INT24_MAX / POSITION_LIMIT) * (x + POSITION_LIMIT);
01544   posFixed24_t result;
01545   result.low = (val >> 0) & 0xFF;
01546   result.middle = (val >> 8) & 0xFF;
01547   result.high = (val >> 16) & 0xFF;
01548   return result;
01549 }
01550 
01551 // assumes input quaternion is normalized. will fail if not.
01552 static inline uint32_t quatcompress(float const q[4])
01553 {
01554   // we send the values of the quaternion's smallest 3 elements.
01555   unsigned i_largest = 0;
01556   for (unsigned i = 1; i < 4; ++i) {
01557     if (fabsf(q[i]) > fabsf(q[i_largest])) {
01558       i_largest = i;
01559     }
01560   }
01561 
01562   // since -q represents the same rotation as q,
01563   // transform the quaternion so the largest element is positive.
01564   // this avoids having to send its sign bit.
01565   unsigned negate = q[i_largest] < 0;
01566 
01567   // 1/sqrt(2) is the largest possible value
01568   // of the second-largest element in a unit quaternion.
01569 
01570   // do compression using sign bit and 9-bit precision per element.
01571   uint32_t comp = i_largest;
01572   for (unsigned i = 0; i < 4; ++i) {
01573     if (i != i_largest) {
01574       unsigned negbit = (q[i] < 0) ^ negate;
01575       unsigned mag = ((1 << 9) - 1) * (fabsf(q[i]) / (float)M_SQRT1_2) + 0.5f;
01576       comp = (comp << 10) | (negbit << 9) | mag;
01577     }
01578   }
01579 
01580   return comp;
01581 }
01582 
01583 void CrazyflieBroadcaster::sendExternalPoses(
01584   const std::vector<externalPose>& data)
01585 {
01586   if (data.size() == 0) {
01587     return;
01588   }
01589 
01590 #if 0
01591   std::vector<crtpExternalPositionPacked> requests(ceil(data.size() / 4.0));
01592   for (size_t i = 0; i < data.size(); ++i) {
01593     size_t j = i / 4;
01594     requests[j].positions[i%4].id = data[i].id;
01595     requests[j].positions[i%4].x = data[i].x * 1000;
01596     requests[j].positions[i%4].y = data[i].y * 1000;
01597     requests[j].positions[i%4].z = data[i].z * 1000;
01598   }
01599 # else
01600   std::vector<crtpPosExtBringup> requests(ceil(data.size() / 2.0));
01601   for (size_t i = 0; i < data.size(); ++i) {
01602     size_t j = i / 2;
01603     requests[j].data.pose[i%2].id = data[i].id;
01604     requests[j].data.pose[i%2].x = position_float_to_fix24(data[i].x);
01605     requests[j].data.pose[i%2].y = position_float_to_fix24(data[i].y);
01606     requests[j].data.pose[i%2].z = position_float_to_fix24(data[i].z);
01607     float q[4] = { data[i].qx, data[i].qy, data[i].qz, data[i].qw };
01608     requests[j].data.pose[i%2].quat = quatcompress(q);
01609   }
01610 #endif
01611 
01612   size_t remainingRequests = requests.size();
01613   size_t i = 0;
01614   while (remainingRequests > 0) {
01615     if (remainingRequests >= 2) {
01616       send2Packets(reinterpret_cast<const uint8_t*>(&requests[i]), 2 * sizeof(crtpExternalPositionPacked));
01617       remainingRequests -= 2;
01618       i += 2;
01619     } else {
01620       sendPacket(reinterpret_cast<const uint8_t*>(&requests[i]), sizeof(crtpExternalPositionPacked));
01621       remainingRequests -= 1;
01622       i += 1;
01623     }
01624   }
01625 }
01626 
01627 // void CrazyflieBroadcaster::setParam(
01628 //   uint8_t group,
01629 //   uint8_t id,
01630 //   Crazyflie::ParamType type,
01631 //   const Crazyflie::ParamValue& value) {
01632 
01633 //   switch (type) {
01634 //     case Crazyflie::ParamTypeUint8:
01635 //       {
01636 //         crtpParamWriteBroadcastRequest<uint8_t> request(group, id, value.valueUint8);
01637 //         sendPacket((const uint8_t*)&request, sizeof(request));
01638 //         break;
01639 //       }
01640 //     case Crazyflie::ParamTypeInt8:
01641 //       {
01642 //         crtpParamWriteBroadcastRequest<int8_t> request(group, id, value.valueInt8);
01643 //         sendPacket((const uint8_t*)&request, sizeof(request));
01644 //         break;
01645 //       }
01646 //     case Crazyflie::ParamTypeUint16:
01647 //       {
01648 //         crtpParamWriteBroadcastRequest<uint16_t> request(group, id, value.valueUint16);
01649 //         sendPacket((const uint8_t*)&request, sizeof(request));
01650 //         break;
01651 //       }
01652 //     case Crazyflie::ParamTypeInt16:
01653 //       {
01654 //         crtpParamWriteBroadcastRequest<int16_t> request(group, id, value.valueInt16);
01655 //         sendPacket((const uint8_t*)&request, sizeof(request));
01656 //         break;
01657 //       }
01658 //     case Crazyflie::ParamTypeUint32:
01659 //       {
01660 //         crtpParamWriteBroadcastRequest<uint32_t> request(group, id, value.valueUint32);
01661 //         sendPacket((const uint8_t*)&request, sizeof(request));
01662 //         break;
01663 //       }
01664 //     case Crazyflie::ParamTypeInt32:
01665 //       {
01666 //         crtpParamWriteBroadcastRequest<int32_t> request(group, id, value.valueInt32);
01667 //         sendPacket((const uint8_t*)&request, sizeof(request));
01668 //         break;
01669 //       }
01670 //     case Crazyflie::ParamTypeFloat:
01671 //       {
01672 //         crtpParamWriteBroadcastRequest<float> request(group, id, value.valueFloat);
01673 //         sendPacket((const uint8_t*)&request, sizeof(request));
01674 //         break;
01675 //       }
01676 //   }
01677 //   // TODO: technically we should update the internal copy of the value of each CF object
01678 // }


crazyflie_tools
Author(s): Wolfgang Hoenig
autogenerated on Wed Jun 12 2019 19:20:48