serial_interface.cpp
Go to the documentation of this file.
00001 /*
00002  *  AscTec Autopilot Serial Interface
00003  *  Copyright (C) 2010, CCNY Robotics Lab
00004  *  William Morris <morris@ee.ccny.cuny.edu>
00005  *  Ivan Dryanovski <ivan.dryanovski@gmail.com>
00006  *  Steven Bellens <steven.bellens@mech.kuleuven.be>
00007  *  Patrick Bouffard <bouffard@eecs.berkeley.edu>
00008  *
00009  *  http://robotics.ccny.cuny.edu
00010  *
00011  *  This program is free software: you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation, either version 3 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public License
00022  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00023  */
00024 
00025 #include <stdio.h>
00026 #include <sys/termios.h>
00027 #include <sys/ioctl.h>
00028 #include <cstring>
00029 #include <cstdlib>
00030 #include <time.h>
00031 #include <errno.h>
00032 #include <bitset>
00033 
00034 #include <ros/ros.h>
00035 
00036 #include "asctec_autopilot/crc16.h"
00037 #include "asctec_autopilot/autopilot.h"
00038 #include "asctec_autopilot/telemetry.h"
00039 #include "asctec_autopilot/serialinterface.h"
00040 
00041 // C++ is a horrible version of C
00042 extern "C" {
00043   #include <unistd.h>
00044   #include <fcntl.h>
00045 }
00046 
00047 namespace asctec
00048 {
00049   SerialInterface::SerialInterface (std::string port, uint32_t speed):serialport_name_ (port), serialport_speed_ (speed)
00050   {
00051     struct termios tio;
00052       status = false;
00053       serialport_baud_ = bitrate (serialport_speed_);
00054       ROS_INFO ("Initializing serial port...");
00055 
00056       dev_ = open(serialport_name_.c_str (),O_RDWR | O_NOCTTY | O_NDELAY);
00057       ROS_DEBUG ("dev: %d", dev_);
00058       ROS_ASSERT_MSG (dev_ != -1, "Failed to open serial port: %s %s", serialport_name_.c_str (), strerror (errno));
00059 
00060       ROS_ASSERT_MSG (tcgetattr (dev_, &tio) == 0, "Unknown Error: %s", strerror (errno));
00061 
00062       cfsetispeed (&tio, serialport_baud_);
00063       cfsetospeed (&tio, serialport_baud_);
00064 
00065       tio.c_iflag = 0;
00066       tio.c_iflag &= ~(BRKINT | ICRNL | IMAXBEL);
00067       tio.c_iflag |= IGNBRK;
00068 
00069       tio.c_oflag = 0;
00070       tio.c_oflag &= ~(OPOST | ONLCR);
00071 
00072       tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8;
00073       tio.c_cflag &= ~(PARENB | CRTSCTS | CSTOPB);
00074 
00075       tio.c_lflag = 0;
00076       tio.c_lflag |= NOFLSH;
00077       tio.c_lflag &= ~(ISIG | IEXTEN | ICANON | ECHO | ECHOE);
00078 
00079       ROS_ASSERT_MSG (tcsetattr (dev_, TCSADRAIN, &tio) == 0, "Unknown Error: %s", strerror (errno));
00080 
00081       tio.c_cc[VMIN] = 0;
00082       tio.c_cc[VTIME] = 0;
00083 
00084       tcflush (dev_, TCIOFLUSH);
00085 
00086       ROS_ASSERT_MSG (dev_ != NULL, "Could not open serial port %s", serialport_name_.c_str ());
00087       ROS_INFO ("Successfully connected to %s, Baudrate %d\n", serialport_name_.c_str (), serialport_speed_);
00088   }
00089 
00090   SerialInterface::~SerialInterface ()
00091   {
00092     ROS_DEBUG ("Destroying Serial Interface");
00093     flush ();
00094     close (dev_);
00095   }
00096 
00097   void SerialInterface::flush ()
00098   {
00099     tcflush (dev_, TCIOFLUSH);
00100   }
00101 
00102   void SerialInterface::drain ()
00103   {
00104     ROS_ASSERT_MSG (tcdrain (dev_) == 0, "Drain Error: %s", strerror (errno));
00105   }
00106 
00107   int SerialInterface::wait (int bytes_requested)
00108   {
00109     int bytes_available=0;
00110     unsigned int i=0;
00111 
00112     while (bytes_available < bytes_requested)
00113     {
00114       ioctl(dev_,FIONREAD,&bytes_available);
00115       usleep(1);
00116       if (i>650 && bytes_available < bytes_requested)
00117       {
00118         ROS_ERROR("Timeout: %d bytes available %d bytes requested",bytes_available,bytes_requested);
00119         return bytes_available;
00120       }
00121       i++;
00122     }
00123     return bytes_available;
00124   }
00125 
00126   speed_t SerialInterface::bitrate (int Bitrate)
00127   {
00128     switch (Bitrate)
00129     {
00130       case 9600:
00131         return B9600;
00132       case 19200:
00133         return B19200;
00134       case 38400:
00135         return B38400;
00136       case 57600:
00137         return B57600;
00138       case 115200:
00139         return B115200;
00140       case 230400:
00141         return B230400;
00142       default:                 // invalid bitrate
00143         return B0;
00144     }
00145   }
00146 
00147   bool SerialInterface::getPacket (char *spacket, unsigned char &packet_type, unsigned short &packet_crc,
00148                                    unsigned short &packet_size)
00149   {
00150     char stoken[4];
00151     char ssize[2];
00152     char stype[1];
00153     char scrc[2];
00154     int bytes;
00155 
00156     int i;
00157 
00158     ROS_DEBUG ("  SerialInterface::getPacket()");
00159     // get beginning (">*>")
00160     stoken[0] = '\0';
00161     stoken[1] = '\0';
00162     stoken[2] = '\0';
00163     stoken[3] = '\0';
00164 
00165     wait(3);
00166     i = read (dev_,stoken, 3);
00167     if (i == 0 || strncmp (stoken, ">*>", 3) != 0)
00168     {
00169       ROS_DEBUG ("    dev: %zd", (size_t) dev_);
00170       ROS_ERROR ("    Error Reading Packet Header: %s", strerror (errno));
00171       ROS_ERROR ("    Read (%d): %s", i, stoken);
00172       //ROS_BREAK();
00173       //while (read (dev_,stoken, 1) != 0) {}
00174       flush ();
00175       return false;
00176     }
00177     serialport_bytes_rx_ += 3;
00178     ROS_DEBUG ("    Packet Header OK");
00179 
00180     // get packet size
00181     wait(2);
00182     i = read (dev_,ssize, 2);
00183     if (i == 0)
00184     {
00185       ROS_ERROR ("Error Reading Packet Size: %s", strerror (errno));
00186       flush ();
00187       return false;
00188     }
00189     serialport_bytes_rx_ += 2;
00190     memcpy (&packet_size, ssize, sizeof (packet_size));
00191     //ROS_DEBUG ("Packet size: %d", packet_size);
00192 
00193     // get packet type
00194     wait(1);
00195     i = read (dev_, stype, 1);
00196     if (i == 0)
00197       return false;
00198     serialport_bytes_rx_ += 1;
00199     memcpy (&packet_type, stype, sizeof (packet_type));
00200     //ROS_DEBUG ("Packet type: %d", packet_type);
00201 
00202     // get packet
00203     wait(packet_size);
00204     i = read (dev_, spacket, packet_size);
00205     if (i == 0)
00206       return false;
00207     serialport_bytes_rx_ += packet_size;
00208     //ROS_DEBUG ("Packet string: ok");
00209 
00210     // get packet crc
00211     wait(2);
00212     i = read (dev_, scrc, 2);
00213     if (i == 0)
00214       return false;
00215     serialport_bytes_rx_ += sizeof (scrc);
00216     memcpy (&packet_crc, scrc, sizeof (packet_crc));
00217     //ROS_DEBUG ("Packet crc: %d", packet_crc);
00218 
00219     // get closing ("<#<")
00220     wait(3);
00221     i = read (dev_, stoken, 3);
00222     if (i == 0 || strncmp (stoken, "<#<", 3) != 0)
00223     {
00224       ROS_ERROR ("Error Reading Packet Footer: %s", strerror (errno));
00225       ROS_DEBUG ("Read (%d): %s", i, stoken);
00226       while (read (dev_, stoken, 1) != 0)
00227       {
00228         stoken[1] = '\0';
00229         ROS_DEBUG ("%s", stoken);
00230       }
00231       flush ();
00232       drain ();
00233       ROS_DEBUG ("Packet Footer Corrupt!!");
00234       return false;
00235     }
00236     serialport_bytes_rx_ += 3;
00237     //ROS_DEBUG ("Packet Footer OK");
00238 
00239     return true;
00240   }
00241 
00242   void SerialInterface::output (char *output, int len)
00243   {
00244     int i;
00245     ROS_DEBUG ("SerialInterface::output()");
00246     serialport_bytes_tx_ += len;
00247     //ROS_DEBUG ("Writing %d element(s): %s", len, output);
00248     //ROS_DEBUG ("dev: %zd", (size_t) dev_);
00249     //flush ();
00250     i = write (dev_, output, len);
00251     if (i != len)
00252     {
00253       ROS_ERROR ("Error wrote %d out of %d element(s): %s", i, len, strerror (errno));
00254       ROS_BREAK ();
00255     }
00256     ROS_DEBUG ("Write completed");
00257   }
00258 
00259   void SerialInterface::output (unsigned char *output, int len)
00260   {
00261     int i;
00262     ROS_DEBUG ("SerialInterface::output()");
00263     serialport_bytes_tx_ += len;
00264     //ROS_INFO ("Writing %d element(s): %s", len, output);
00265     //ROS_DEBUG ("dev: %zd", (size_t) dev_);
00266     //ROS_DEBUG ("FOO");
00267     i = write (dev_, output, len);
00268     if (i != len)
00269     {
00270       ROS_ERROR ("Error wrote %d out of %d element(s): %s", i, len, strerror (errno));
00271       ROS_BREAK ();
00272     }
00273   }
00274   void SerialInterface::sendControl (Telemetry * telemetry)
00275   {
00276     int i;
00277     char data[5];
00278 
00279     if(!telemetry->controlEnabled_) return;
00280     //ROS_DEBUG ("sendControl started");
00281     flush();
00282     unsigned char cmd[] = ">*>di";
00283     //telemetry->dumpCTRL_INPUT();
00284     if (telemetry->controlInterval_ != 0 && ((telemetry->controlCount_ - telemetry->controlOffset_) % telemetry->controlInterval_ == 0)) {
00285       if(telemetry->CTRL_INPUT_.chksum != telemetry->CTRL_INPUT_.pitch + telemetry->CTRL_INPUT_.roll + telemetry->CTRL_INPUT_.yaw + telemetry->CTRL_INPUT_.thrust + telemetry->CTRL_INPUT_.ctrl + (short) 0xAAAA){
00286         //ROS_INFO("invalid CtrlInput checksum: %d !=  %d", telemetry->CTRL_INPUT_.chksum, telemetry->CTRL_INPUT_.pitch + telemetry->CTRL_INPUT_.roll + telemetry->CTRL_INPUT_.yaw + telemetry->CTRL_INPUT_.thrust + telemetry->CTRL_INPUT_.ctrl + (short) 0xAAAA);
00287         return;
00288       }
00289       output(cmd,5);
00290       output((unsigned char*) &telemetry->CTRL_INPUT_, 12);
00291       //ROS_INFO("writing control to pelican: size of CTRL_INPUT_ %zd", sizeof(telemetry->CTRL_INPUT_));
00292       wait(5);
00293       //ROS_INFO("Data Available");
00294       i = read (dev_,data,5);
00295       if (i != 5) {
00296         ROS_ERROR("Control Response : Insufficient Data");
00297         flush();
00298         return;
00299       }
00300       if (strncmp(data,">a",2) != 0) {
00301         ROS_ERROR("Corrupt Response Header %c%c (%0x%0x)",data[0],data[1],data[0],data[1]);
00302         flush();
00303         return;
00304       }
00305       if (strncmp(data+3,"a<",2) != 0) {
00306         ROS_ERROR("Corrupt Response Footer %c%c (%0x%0x)",data[3],data[4],data[3],data[4]);
00307         flush();
00308         return;
00309       }
00310       ROS_DEBUG("Control Response Code %0x",data[2]);
00311     }
00312     //ROS_INFO ("sendControl completed" );
00313   }
00314 
00315   void SerialInterface::sendEstop(Telemetry * telemetry)
00316   {
00317     static bool sent_estop_reported = false;
00318     if (!telemetry->controlEnabled_)
00319       return;
00320     //ROS_DEBUG ("sendControl started");
00321     flush();
00322     unsigned char cmd[] = ">*>me";
00323     output(cmd, 5);
00324     if (!sent_estop_reported)
00325     {
00326       ROS_WARN("Sent E-Stop command!");
00327       sent_estop_reported = true;
00328     }
00329   }
00330 
00331   bool SerialInterface::getPackets (Telemetry * telemetry)
00332   {
00333     flush ();
00334     ROS_DEBUG ("SerialInterface::getPackets");
00335     char cmd[16];
00336     char spacket[1024];
00337     unsigned char packet_type;
00338     unsigned short packet_crc;
00339     unsigned short packet_size;
00340     unsigned int i;
00341     bool result = false;
00342     ros::Time packetTime;
00343 
00344     ROS_DEBUG ("  Requesting %04x %zd packets", (short) telemetry->requestPackets_.to_ulong (),
00345               telemetry->requestPackets_.count ());
00346     sprintf (cmd, ">*>p%c", (short) telemetry->requestPackets_.to_ulong ());
00347     output (cmd, 6);
00348 
00349     for (i = 0; i < telemetry->requestPackets_.count (); i++)
00350     {
00351       packetTime = ros::Time::now();  // Presumes that the AutoPilot is grabbing the data for each packet
00352                                       // immediately prior to each packet being sent, as opposed to gathering
00353                                       // all the data at once and then sending it all. Either way is a guess
00354                                       // unless we get some info from AscTec one way or the other..
00355       bool read_result = getPacket (spacket, packet_type, packet_crc, packet_size);
00356 
00357       if (read_result)
00358       {
00359         ROS_DEBUG ("  Read successful: type = %d, crc = %d", packet_type, packet_crc);
00360 
00361         if (packet_type == Telemetry::PD_LLSTATUS)
00362         {
00363           ROS_DEBUG ("  Packet type is LL_STATUS");
00364           memcpy (&telemetry->LL_STATUS_, spacket, packet_size);
00365           telemetry->timestamps_[RequestTypes::LL_STATUS] = packetTime;
00366           if (crc_valid (packet_crc, &telemetry->LL_STATUS_, sizeof (packet_size)))
00367           {
00368             result = true;
00369           }
00370           //telemetry->dumpLL_STATUS();
00371         }
00372         else if (packet_type == Telemetry::PD_IMURAWDATA)
00373         {
00374           ROS_DEBUG ("  Packet type is IMU_RAWDATA");
00375           memcpy (&telemetry->IMU_RAWDATA_, spacket, packet_size);
00376           telemetry->timestamps_[RequestTypes::IMU_RAWDATA] = packetTime;
00377           if (crc_valid (packet_crc, &telemetry->IMU_RAWDATA_, packet_size))
00378           {
00379             result = true;
00380           }
00381           //telemetry->dumpIMU_RAWDATA();
00382         }
00383         else if (packet_type == Telemetry::PD_IMUCALCDATA)
00384         {
00385           ROS_DEBUG ("  Packet type is IMU_CALCDATA");
00386           memcpy (&telemetry->IMU_CALCDATA_, spacket, packet_size);
00387           telemetry->timestamps_[RequestTypes::IMU_CALCDATA] = packetTime;
00388           if (crc_valid (packet_crc, &telemetry->IMU_CALCDATA_, packet_size))
00389           {
00390             result = true;
00391           }
00392           //telemetry->dumpIMU_CALCDATA();
00393         }
00394         else if (packet_type == Telemetry::PD_RCDATA)
00395         {
00396           ROS_DEBUG ("  Packet type is RC_DATA");
00397           memcpy (&telemetry->RC_DATA_, spacket, packet_size);
00398           telemetry->timestamps_[RequestTypes::RC_DATA] = packetTime;
00399           if (crc_valid (packet_crc, &telemetry->RC_DATA_, packet_size))
00400           {
00401             result = true;
00402           }
00403           //telemetry->dumpRC_DATA();
00404         }
00405         else if (packet_type == Telemetry::PD_CTRLOUT)
00406         {
00407           ROS_DEBUG ("  Packet type is CONTROLLER_OUTPUT");
00408           memcpy (&telemetry->CONTROLLER_OUTPUT_, spacket, packet_size);
00409           telemetry->timestamps_[RequestTypes::CONTROLLER_OUTPUT] = packetTime;
00410           if (crc_valid (packet_crc, &telemetry->CONTROLLER_OUTPUT_, packet_size))
00411           {
00412             result = true;
00413           }
00414           //telemetry->dumpCONTROLLER_OUTPUT();
00415         }
00416         else if (packet_type == Telemetry::PD_GPSDATA)
00417         {
00418           ROS_DEBUG ("  Packet type is GPS_DATA");
00419           memcpy (&telemetry->GPS_DATA_, spacket, packet_size);
00420           telemetry->timestamps_[RequestTypes::GPS_DATA] = packetTime;
00421           if (crc_valid (packet_crc, &telemetry->GPS_DATA_, packet_size))
00422           {
00423             result = true;
00424           }
00425           //telemetry->dumpGPS_DATA();
00426         }
00427         else if (packet_type == Telemetry::PD_GPSDATAADVANCED)
00428         {
00429           ROS_DEBUG ("  Packet type is GPS_DATA_ADVANCED");
00430           memcpy (&telemetry->GPS_DATA_ADVANCED_, spacket, packet_size);
00431           telemetry->timestamps_[RequestTypes::GPS_DATA_ADVANCED] = packetTime;
00432           if (crc_valid (packet_crc, &telemetry->GPS_DATA_ADVANCED_, packet_size))
00433           {
00434             result = true;
00435           }
00436           //telemetry->dumpGPS_DATA_ADVANCED();
00437         }
00438         else
00439         {
00440           ROS_ERROR ("  Packet type (%#2x) is UNKNOWN", packet_type);
00441         }
00442       }
00443       else
00444       {
00445         // failed read
00446         ROS_ERROR ("  Read failed");
00447         break;
00448       }
00449     }
00450     ioctl(dev_,FIONREAD,&i);
00451     if (i != 0)
00452     {
00453       ROS_ERROR ("  Unexpected Data: Flushing receive buffer");
00454       flush();
00455     }
00456     return result;
00457   }
00458 }
00459 


asctec_autopilot
Author(s): William Morris, Ivan Dryanovski, Steven Bellens, Patrick Bouffard et al.
autogenerated on Tue Jan 7 2014 11:04:25