serial_gateway.cpp
Go to the documentation of this file.
00001 
00025 #include "puma_motor_driver/serial_gateway.h"
00026 #include "ros/ros.h"
00027 
00028 namespace puma_motor_driver
00029 {
00030 
00031 SerialGateway::SerialGateway(serial::Serial& serial) : serial_(serial),
00032   write_buffer_index_(0), read_buffer_index_(0), read_buffer_len_(0)
00033 {
00034   serial::Timeout to(serial::Timeout::simpleTimeout(50));
00035   serial_.setTimeout(to);
00036   serial_.setBaudrate(115200);
00037 }
00038 
00039 bool SerialGateway::connect()
00040 {
00041   if (!serial_.isOpen())
00042   {
00043     try
00044     {
00045       serial_.open();
00046     }
00047     catch (std::exception& e)
00048     {
00049       ROS_ERROR("Exception thrown trying to open %s: %s", serial_.getPort().c_str(), e.what());
00050       return false;
00051     }
00052     return true;
00053   }
00054   return false;
00055 }
00056 
00057 bool SerialGateway::isConnected()
00058 {
00059   return serial_.isOpen();
00060 }
00061 
00062 void SerialGateway::queue(const Message& msg)
00063 {
00064   ROS_DEBUG_NAMED("serial", "Queuing ID 0x%08x, data (%d)", msg.id, msg.len);
00065 
00066   queue('\xff');
00067   queue(4 + msg.len);
00068 
00069   encodeAndQueue(reinterpret_cast<uint8_t*>(msg.id), 4);
00070   encodeAndQueue(msg.data, msg.len);
00071 }
00072 
00073 bool SerialGateway::recv(Message* msg)
00074 {
00075   int bytes_dropped = 0;
00076 
00077   // Look for header byte.
00078   while (1)
00079   {
00080     uint8_t header_byte;
00081     if (!read(&header_byte))
00082     {
00083       ROS_DEBUG_NAMED("serial", "Header byte read timed out. No more messages for now.");
00084       return false;
00085     }
00086 
00087     if (header_byte != 0xff)
00088     {
00089       bytes_dropped++;
00090       continue;
00091     }
00092 
00093     ROS_WARN_COND_NAMED(bytes_dropped > 0, "serial", "Discarded %d bytes between messages.", bytes_dropped);
00094     break;
00095   }
00096 
00097   uint8_t len_byte;
00098   if (!read(&len_byte))
00099   {
00100     ROS_WARN_NAMED("serial", "Len byte read timed out.");
00101     return false;
00102   }
00103   if (len_byte < 4 || len_byte > 12)
00104   {
00105     ROS_WARN_NAMED("serial", "Illegal length byte value, dropping message.");
00106     return false;
00107   }
00108 
00109   // CAN ID in little endian.
00110   if (!readAndDecode(reinterpret_cast<uint8_t*>(msg->id), 4))
00111   {
00112     ROS_WARN_NAMED("serial", "Problem reading ID, dropping message.");
00113     return false;
00114   }
00115 
00116   // CAN data.
00117   msg->len = len_byte - 4;
00118   if (!readAndDecode(msg->data, msg->len))
00119   {
00120     ROS_WARN_NAMED("serial", "Problem reading %d data bytes for ID 0x%08x, dropping message.", msg->len, msg->id);
00121     return false;
00122   }
00123 
00124   ROS_DEBUG_NAMED("serial", "Received ID 0x%08x, data (%d)", msg->id, msg->len);
00125   return true;
00126 }
00127 
00128 void SerialGateway::queue(uint8_t ch)
00129 {
00130   if (write_buffer_index_ < sizeof(write_buffer_))
00131   {
00132     write_buffer_[write_buffer_index_] = ch;
00133     write_buffer_index_++;
00134   }
00135 }
00136 
00137 bool SerialGateway::read(uint8_t* ch)
00138 {
00139   // If buffer is exhausted, attempt to request more from the hardware.
00140   if (read_buffer_index_ >= read_buffer_len_)
00141   {
00142     read_buffer_index_ = 0;
00143     read_buffer_len_ = serial_.read(read_buffer_, sizeof(read_buffer_));
00144     ROS_DEBUG_NAMED("serial", "Filled read buffer with %d bytes.", read_buffer_len_);
00145 
00146     if (read_buffer_len_ < 1)
00147     {
00148       // Read operation returned nothing, therefore there is no character
00149       // to return here.
00150       return false;
00151     }
00152   }
00153 
00154   *ch = read_buffer_[read_buffer_index_];
00155   read_buffer_index_++;
00156   return true;
00157 }
00158 
00159 bool SerialGateway::sendAllQueued()
00160 {
00161   try
00162   {
00163     uint8_t written = serial_.write(write_buffer_, write_buffer_index_);
00164 
00165     if (written < write_buffer_index_)
00166     {
00167       ROS_WARN_STREAM("Write to serial port timed out. Tried to write " <<
00168           write_buffer_index_ << " bytes, instead wrote only " << written << ". Remainder dropped.");
00169       write_buffer_index_ = 0;
00170       return false;
00171     }
00172     ROS_DEBUG_NAMED("serial", "Wrote %d bytes to serial port.", written);
00173   }
00174   catch (std::exception& e)
00175   {
00176     ROS_ERROR("Exception thrown trying to write to %s: %s", serial_.getPort().c_str(), e.what());
00177     serial_.close();
00178   }
00179 
00180   write_buffer_index_ = 0;
00181   return true;
00182 }
00183 
00184 void SerialGateway::encodeAndQueue(const uint8_t* data, uint8_t len)
00185 {
00186   for (uint8_t index = 0; index < len; index++)
00187   {
00188     switch (data[index])
00189     {
00190       case 0xff:
00191         queue('\xfe');
00192         queue('\xfe');
00193         break;
00194       case 0xfe:
00195         queue('\xfe');
00196         queue('\xfd');
00197         break;
00198       default:
00199         queue(data[index]);
00200     }
00201   }
00202 }
00203 
00204 bool SerialGateway::readAndDecode(uint8_t* data, uint8_t len)
00205 {
00206   for (uint8_t index = 0; index < len; index++)
00207   {
00208     uint8_t undecoded_byte;
00209     if (!read(&undecoded_byte))
00210     {
00211       ROS_WARN_NAMED("serial", "Read of undecoded byte timed out.");
00212       return false;
00213     }
00214 
00215     switch (undecoded_byte)
00216     {
00217       case 0xff:
00218         ROS_WARN_NAMED("serial", "Unexpected start-of-message character.");
00219         return false;
00220       case 0xfe:
00221         uint8_t second_byte;
00222         if (!read(&second_byte))
00223         {
00224           ROS_WARN_NAMED("serial", "Read of second byte in decoded pair timed out.");
00225           return false;
00226         }
00227         switch (second_byte)
00228         {
00229           case 0xfe:
00230             data[index] = '\xff';
00231             break;
00232           case 0xfd:
00233             data[index] = '\xfe';
00234             break;
00235           default:
00236             ROS_WARN_NAMED("serial", "Unexpected second byte in encoded sequence.");
00237             return false;
00238         }
00239         break;
00240       default:
00241         data[index] = undecoded_byte;
00242     }
00243   }
00244   return true;
00245 }
00246 
00247 }  // namespace puma_motor_driver


puma_motor_driver
Author(s):
autogenerated on Sat Jun 8 2019 18:55:15