MSP.cpp
Go to the documentation of this file.
00001 #include "MSP.hpp"
00002 
00003 #include <future>
00004 #include <iostream>
00005 #include <type_traits>
00006 
00007 namespace msp {
00008 
00009 MSP::MSP() : port(io), wait(10) { }
00010 
00011 MSP::MSP(const std::string &device, const uint baudrate) : port(io), wait(10) {
00012     connect(device, baudrate);
00013 }
00014 
00015 bool MSP::connect(const std::string &device, const uint baudrate) {
00016     this->device = device;
00017     try {
00018         port.open(device);
00019     }
00020     catch(const asio::system_error &e) {
00021         throw NoConnection(device, e.what());
00022     }
00023 
00024     port.set_option(asio::serial_port::baud_rate(baudrate));
00025     port.set_option(asio::serial_port::parity(asio::serial_port::parity::none));
00026     port.set_option(asio::serial_port::character_size(asio::serial_port::character_size(8)));
00027     port.set_option(asio::serial_port::stop_bits(asio::serial_port::stop_bits::one));
00028 
00029     // clear buffer for new session
00030     clear();
00031 
00032     std::cout<<"Connected to: "<<device<<std::endl;
00033     return true;
00034 }
00035 
00036 bool MSP::request(msp::Request &request) {
00037     if(!sendData(request.id()))
00038         return false;
00039 
00040     std::this_thread::sleep_for(std::chrono::microseconds(wait));
00041 
00042     try {
00043         const DataID pkg = receiveData();
00044         if(pkg.id==uint8_t(request.id()))
00045             request.decode(pkg.data);
00046         return pkg.id==uint8_t(request.id());
00047     }
00048     catch(const MalformedHeader &e) {
00049         std::cerr<<e.what()<<std::endl;
00050         return false;
00051     }
00052     catch(const WrongCRC &e) {
00053         std::cerr<<e.what()<<std::endl;
00054         return false;
00055     }
00056     catch(const UnknownMsgId &e) {
00057         if(e.getInvalidID()==uint8_t(request.id())) {
00058             std::cerr<<e.what()<<std::endl;
00059         }
00060         return false;
00061     }
00062     catch(msp::NoData) { return false; }
00063     catch(asio::system_error) { return false; }
00064 }
00065 
00066 bool MSP::request_block(msp::Request &request) {
00067     bool success = false;
00068     while(success==false) {
00069         // write ID
00070         if(!sendData(request.id())) {
00071             success = false;
00072             continue;
00073         }
00074 
00075         std::this_thread::sleep_for(std::chrono::microseconds(wait));
00076 
00077         try {
00078             const DataID pkg = receiveData();
00079             success = (pkg.id==uint8_t(request.id()));
00080             if(success)
00081                 request.decode(pkg.data);
00082         }
00083         catch(const MalformedHeader &e) {
00084             std::cerr<<e.what()<<std::endl;
00085             success = false;
00086         }
00087         catch(const WrongCRC &e) {
00088             std::cerr<<e.what()<<std::endl;
00089             success = false;
00090         }
00091         catch(const UnknownMsgId &e) {
00092             if(e.getInvalidID()==uint8_t(request.id())) {
00093                 std::cerr<<e.what()<<std::endl;
00094                 return false;
00095             }
00096             success = false;
00097         }
00098         catch(msp::NoData) { success = false; }
00099         catch(asio::system_error) { success = false; }
00100     }
00101 
00102     return true;
00103 }
00104 
00105 bool MSP::request_wait(msp::Request &request, const uint wait_ms, const uint min_payload_size) {
00106     const std::chrono::milliseconds wait(wait_ms);
00107 
00108     bool success = false;
00109     while(success==false) {
00110         // send ID
00111         while(sendData(request.id())!=true);
00112 
00113         std::this_thread::sleep_for(wait);
00114 
00115         try {
00116             if(hasData()>=int(FRAME_SIZE+min_payload_size)) {
00117                 DataID pkg = receiveData();
00118                 success = (pkg.id==uint8_t(request.id()));
00119                 if(success)
00120                     request.decode(pkg.data);
00121             }
00122         }
00123         catch(const MalformedHeader &e) {
00124             std::cerr<<e.what()<<std::endl;
00125             success = false;
00126         }
00127         catch(const WrongCRC &e) {
00128             std::cerr<<e.what()<<std::endl;
00129             success = false;
00130         }
00131         catch(const UnknownMsgId &e) {
00132             if(e.getInvalidID()==uint8_t(request.id())) {
00133                 std::cerr<<e.what()<<std::endl;
00134                 return false;
00135             }
00136             success = false;
00137         }
00138         catch(msp::NoData) { success = false; }
00139         catch(asio::system_error) { success = false; }
00140     }
00141 
00142     return true;
00143 }
00144 
00145 bool MSP::respond(const msp::Response &response) {
00146     if(!sendData(response.id(), response.encode()))
00147         return false;
00148 
00149     std::this_thread::sleep_for(std::chrono::microseconds(wait));
00150 
00151     try {
00152         const DataID pkg = receiveData();
00153         return (pkg.id==uint8_t(response.id()) && pkg.data.size()==0);
00154     }
00155     catch(const MalformedHeader &e) {
00156         std::cerr<<e.what()<<std::endl;
00157         return false;
00158     }
00159     catch(asio::system_error) { return false; }
00160 }
00161 
00162 bool MSP::respond_block(const msp::Response &response) {
00163     bool success = false;
00164     while(success==false) {
00165         // write ID and data and skip to write again if error occurred
00166         if(!sendData(response.id(), response.encode())) {
00167             success = false;
00168             continue;
00169         }
00170 
00171         try {
00172             const DataID pkg = receiveData();
00173             success = (pkg.id==uint8_t(response.id()) && pkg.data.size()==0);
00174         }
00175         catch(const MalformedHeader &e) {
00176             std::cerr<<e.what()<<std::endl;
00177             success = false;
00178         }
00179         catch(msp::NoData) { success = false; }
00180         catch(asio::system_error) { success = false; }
00181     }
00182 
00183     return true;
00184 }
00185 
00186 bool MSP::sendData(const uint8_t id, const ByteVector &data) {
00187     ByteVector msg;
00188     msg.reserve(6+data.size());
00189 
00190     msg.push_back('$');
00191     msg.push_back('M');
00192     msg.push_back('<');
00193     msg.push_back(uint8_t(data.size()));                // data size
00194     msg.push_back(id);                                  // message_id
00195     msg.insert(msg.end(), data.begin(), data.end());    // data
00196     msg.push_back( crc(id, data) );                     // crc
00197 
00198     return write(msg);
00199 }
00200 
00201 DataID MSP::receiveData() {
00202     // wait for correct preamble start
00203     if(hasData()<1) {
00204         throw NoData();
00205     }
00206 
00207     while( char(read()) != '$');
00208 
00209     const char hdr = char(read());
00210     if(hdr != 'M')
00211         throw MalformedHeader('M', uint8_t(hdr));
00212 
00213     const char com_state = char(read());
00214     if(com_state != '>') {
00215         switch(com_state) {
00216         case '!': {
00217             // the sent message ID is unknown to the FC
00218             read(); // ignore data size
00219             const uint8_t id = read(); // get faulty ID
00220             throw UnknownMsgId(id);
00221         }
00222         default:
00223             throw MalformedHeader('>', uint8_t(com_state));
00224         }
00225     }
00226 
00227     // read data size
00228     const uint8_t data_size = read();
00229 
00230     // get ID of msg
00231     const uint8_t id = read();
00232 
00233     // read payload data
00234     const ByteVector data = read(data_size);
00235 
00236     // check CRC
00237     const uint8_t rcv_crc = read();
00238     const uint8_t exp_crc = crc(id, data);
00239 
00240     if(rcv_crc!=exp_crc)
00241         throw WrongCRC(id, exp_crc, rcv_crc);
00242 
00243     return DataID(data,id);
00244 }
00245 
00246 uint8_t MSP::crc(const uint8_t id, const ByteVector &data) {
00247     uint8_t crc = uint8_t(data.size())^id;
00248 
00249     for(uint8_t d : data)
00250         crc = crc^d;
00251 
00252     return crc;
00253 }
00254 
00255 bool MSP::write(const std::vector<uint8_t> &data) {
00256     std::lock_guard<std::mutex> lock(lock_write);
00257     try {
00258         const std::size_t bytes_written = asio::write(port, asio::buffer(data.data(), data.size()));
00259         return (bytes_written==data.size());
00260     }
00261     catch(const asio::system_error &e) {
00262         throw NoConnection(device, e.what());
00263     }
00264 }
00265 
00266 size_t MSP::read(std::vector<uint8_t> &data) {
00267     std::lock_guard<std::mutex> lock(lock_read);
00268     return asio::read(port, asio::buffer(data.data(), data.size()));
00269 }
00270 
00271 std::vector<uint8_t> MSP::read(std::size_t n_bytes) {
00272     std::vector<uint8_t> data(n_bytes);
00273     const size_t nread = read(data);
00274     assert(nread==n_bytes);
00275     return data;
00276 }
00277 
00278 int MSP::hasData() {
00279 #if __unix__ || __APPLE__
00280     int available_bytes;
00281     if(ioctl(port.native_handle(), FIONREAD, &available_bytes)!=-1) {
00282         return available_bytes;
00283     }
00284     else {
00285         return -1;
00286     }
00287 #elif _WIN32
00288     COMSTAT comstat;
00289     if (ClearCommError(port.native_handle(), NULL, &comstat) == true) {
00290         return comstat.cbInQue;
00291     }
00292     else {
00293         return -1;
00294     }
00295 #else
00296 #warning "hasData() will be unimplemented"
00297 #endif
00298 }
00299 
00300 void MSP::clear() {
00301 #if __unix__ || __APPLE__
00302     tcflush(port.native_handle(),TCIOFLUSH);
00303 #elif _WIN32
00304     PurgeComm(port.native_handle(), PURGE_TXCLEAR);
00305 #else
00306 #warning "clear() will be unimplemented"
00307 #endif
00308 }
00309 
00310 } // namespace msp


msp
Author(s): Christian Rauch
autogenerated on Mon Oct 9 2017 03:02:13