Serial.cpp
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of FZIs ic_workspace.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2014 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00012 //
00013 // -- END LICENSE BLOCK ------------------------------------------------
00014 
00015 //----------------------------------------------------------------------
00028 //----------------------------------------------------------------------
00029 
00030 // Not functional with Mac OS X (UH)
00031 
00032 #include "icl_comm_serial/Serial.h"
00033 
00034 #include <cassert>
00035 #include <algorithm>
00036 
00037 #include <icl_core/os_lxrt.h>
00038 
00039 #ifdef _SYSTEM_LXRT_
00040 # include <sys/mman.h>
00041 # include <rtai_serial.h>
00042 #endif
00043 
00044 #ifdef _SYSTEM_LINUX_
00045 # include <stdio.h>
00046 # include <fcntl.h>
00047 # include <sys/time.h>
00048 # include <errno.h>
00049 # include <string.h>
00050 #endif
00051 
00052 #include "icl_core/TimeStamp.h"
00053 #include "icl_core/TimeSpan.h"
00054 //#include "mcal_math/OwnMath.h"
00055 
00056 #ifdef _SYSTEM_WIN32_
00057 #include <math.h>
00058 #include <stdio.h>
00059 #endif
00060 
00061 #undef SERIAL_DUMP_DATA
00062 //#define SERIAL_DUMP_DATA
00063 
00064 // Work around a typo in older RTAI serial drivers.
00065 #if defined(_SYSTEM_LXRT_33_) || defined(_SYSTEM_LXRT_35_)
00066 # define rt_spset_mcr(tty, mask, setbits) rt_spset_msr(tty, mask, setbits)
00067 #endif
00068 
00069 namespace icl_comm  {
00070 namespace serial {
00071 
00072   Serial::Serial(const char *dev_name, const SerialFlags& flags)
00073     :m_dev_name(strdup(dev_name)),
00074      m_serial_flags(flags)
00075   {
00076   #ifdef _SYSTEM_WIN32_
00077     m_com=INVALID_HANDLE_VALUE;
00078   #else
00079     file_descr=-1;
00080     is_lxrt_serial = false;
00081   #endif
00082 
00083     Open();
00084   }
00085 
00086   Serial::Serial(const char *dev_name, SerialFlags::BaudRate baud_rate, const SerialFlags& flags)
00087     :m_dev_name(strdup(dev_name)),
00088      m_serial_flags(flags)
00089   {
00090   #ifdef _SYSTEM_WIN32_
00091     m_com=INVALID_HANDLE_VALUE;
00092   #else
00093     file_descr=-1;
00094     is_lxrt_serial = false;
00095   #endif
00096 
00097     m_serial_flags.setBaudRate(baud_rate);
00098     Open();
00099   }
00100 
00101   bool Serial::Open()
00102   {
00103     Close();
00104 
00105   #if defined _SYSTEM_LINUX_
00106   #ifdef _SYSTEM_LXRT_
00107     if (icl_core::os::IsThisLxrtTask() && IsLXRTDeviceName(m_dev_name))
00108     {
00109       is_lxrt_serial = true;
00110       int baud= m_serial_flags.getBaudRate();
00111       int numbits;
00112       switch (m_serial_flags.DataBits())
00113       {
00114         case SerialFlags::eDB_5:
00115           numbits = 5;
00116           break;
00117         case SerialFlags::eDB_6:
00118           numbits = 6;
00119           break;
00120         case SerialFlags::eDB_7:
00121           numbits = 7;
00122           break;
00123         case SerialFlags::eDB_8:
00124           numbits = 8;
00125           break;
00126         default:
00127           numbits = 8;
00128       }
00129 
00130       int stopbits;
00131       if (m_serial_flags.StopBits())
00132         stopbits = 2;
00133       else
00134         stopbits = 1;
00135 
00136       int parity=0;
00137       switch (m_serial_flags.Parity())
00138       {
00139         case SerialFlags::eP_EVEN:
00140         {
00141           parity = RT_SP_PARITY_EVEN;
00142           break;
00143         }
00144         case SerialFlags::eP_ODD:
00145         {
00146           parity = RT_SP_PARITY_ODD;
00147           break;
00148         }
00149         case SerialFlags::eP_NONE:
00150         case SerialFlags::eP_MARK:
00151         case SerialFlags::eP_SPACE:
00152         {
00153           parity = RT_SP_PARITY_NONE;
00154           break;
00155         }
00156       }
00157 
00158       int mode=0;
00159       switch (m_serial_flags.FlowControl())
00160       {
00161         case SerialFlags::eFC_FLOW:
00162         {
00163           mode = RT_SP_HW_FLOW;
00164           break;
00165         }
00166         case SerialFlags::eFC_HAND_SHAKE:
00167         {
00168           mode = RT_SP_NO_HAND_SHAKE;
00169           break;
00170         }
00171       }
00172 
00173       int fifotrig = RT_SP_FIFO_SIZE_DEFAULT;
00174 
00175       LOGGING_INFO_C(SERIAL, Serial, "Using LXRT extension for accessing serial device " << tty << " (" << m_dev_name << "): " <<
00176                       baud << " " << numbits << " " << stopbits << " " << parity << " " << mode << " " << fifotrig << endl);
00177       //INFOMSG("Using LXRT extension for accessing serial device %i (%s): %i %i %i %x %x %i\n", tty, m_dev_name, baud, numbits, stopbits, parity, mode, fifotrig);
00178       if ((m_status = rt_spopen(tty, baud, numbits, stopbits, parity, mode, fifotrig)) < 0)
00179       {
00180         LOGGING_DEBUG_C(SERIAL, Serial, "Cannot open lxrt serial device '" << tty << " (" << m_dev_name << ")'. Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00181         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Cannot open lxrt serial device '%i (%s)'. Status (%i:%s)\n", tty, m_dev_name, m_status, strerror(-m_status));
00182         return false;
00183       }
00184       else
00185       {
00186         file_descr = tty;
00187         m_status = 0;
00188 
00189         if (m_serial_flags.getModemControlFlags()!=SerialFlags::eMCF_UNDEFINED)
00190         {
00191           LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ") setting hardware modem control flags to 0x" << m_serial_flags.getModemControlFlags() << endl);
00192           //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s) setting hardware modem control flags to 0x%x\n", m_dev_name, m_serial_flags.getModemControlFlags());
00193 
00194           int mask = 0;
00195           // setting the mask to all set bits
00196           if (m_serial_flags.getModemControlFlags() & SerialFlags::eMCF_RTS)
00197             mask |= RT_SP_RTS;
00198           if (m_serial_flags.getModemControlFlags() & SerialFlags::eMCF_DTR)
00199             mask |= RT_SP_DTR;
00200 
00201           int ret = rt_spset_mcr(tty, mask, 1);
00202           //LDM("rt_spset_mcr(%i, %x, 1)=%i\n", tty, mask, ret);
00203 
00204           // the zero-bits also have to be cleared explicitly, so change the mask for that
00205           // setting the mask to all bits not set
00206           mask = 0;
00207           if (~(m_serial_flags.getModemControlFlags() & SerialFlags::eMCF_RTS))
00208             mask |= RT_SP_RTS;
00209           if (~(m_serial_flags.getModemControlFlags() & SerialFlags::eMCF_DTR))
00210             mask |= RT_SP_DTR;
00211 
00212           ret = rt_spset_mcr(tty, mask, 0);
00213           //LDM("rt_spset_mcr(%i, %x, 0)=%i\n", tty, mask, ret);
00214         }
00215       }
00216     }
00217     else
00218   #endif
00219     // Attention! The following code will be executed,
00220     // if we are not a lxrt-task or no lxrt interface is available:
00221     {
00222 
00223       termios io_set_new;
00224 
00225       // open device
00226       if ((file_descr = open(m_dev_name, O_RDWR | O_NONBLOCK)) < 0)
00227       {
00228         m_status = -errno;
00229         LOGGING_DEBUG_C(SERIAL, Serial, "Cannot open serial device '" << m_dev_name << "'. Status (" << m_status << ":" << strerror(-m_status) << endl);
00230         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Cannot open serial device '%s'. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00231         return false;
00232       }
00233       else
00234         m_status = 0;
00235 
00236       // get device-settings
00237       if (tcgetattr(file_descr, &io_set_old) < 0)
00238       {
00239         m_status = -errno;
00240         LOGGING_DEBUG_C(SERIAL, Serial,  "Cannot get serial device m_status '" << m_dev_name << "'. Status (" << m_status << ":" << strerror(-m_status) << endl);
00241         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Cannot get serial device m_status '%s'. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00242         return false;
00243       }
00244       else
00245         m_status = 0;
00246 
00247       // copy settings from old settings
00248       io_set_new = io_set_old;
00249 
00250       // declare new settings
00251       io_set_new.c_cflag = m_serial_flags.CFlags();
00252       io_set_new.c_oflag = 0;
00253       io_set_new.c_iflag = IGNPAR;
00254       io_set_new.c_lflag = 0;
00255       io_set_new.c_cc[VMIN] = 1;
00256       io_set_new.c_cc[VTIME] = 0;
00257 
00258       // set new settings
00259       if (tcsetattr(file_descr, TCSANOW, &io_set_new) < 0)
00260       {
00261         m_status = -errno;
00262         LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ") Error>> tcsetattr failed. Status (" << m_status << ":" << strerror(-m_status) << endl);
00263         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s) Error>> tcsetattr failed. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00264         return false;
00265       }
00266       else
00267         m_status = 0;
00268 
00269       if (m_serial_flags.getModemControlFlags()!=SerialFlags::eMCF_UNDEFINED)
00270       {
00271         LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ") setting hardware modem control flags to 0x" << m_serial_flags.getModemControlFlags() << endl);
00272         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s) setting hardware modem control flags to 0x%x\n", m_dev_name, m_serial_flags.getModemControlFlags());
00273         int modem_control_flags=0;
00274         if (m_serial_flags.getModemControlFlags() & SerialFlags::eMCF_DTR)
00275         {
00276           modem_control_flags |= TIOCM_DTR;
00277         }
00278         if (m_serial_flags.getModemControlFlags() & SerialFlags::eMCF_RTS)
00279         {
00280           modem_control_flags |= TIOCM_RTS;
00281         }
00282 
00283         ioctl(file_descr, TIOCMSET, modem_control_flags);
00284       }
00285     }
00286 
00287   #elif defined _SYSTEM_WIN32_
00288 
00289     m_read_buffer_fill = 0;
00290     m_status = 0;
00291 
00292     // Try to open the serial port.
00293     m_com = CreateFile(m_dev_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
00294     if (m_com == INVALID_HANDLE_VALUE)
00295     {
00296       m_status = GetLastError();
00297       LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> open port failed (" << StatusText().c_str() << ")." << endl);
00298       //WARNINGMSG("Serial(%s): ERROR>> open port failed (%s).\n", m_dev_name, StatusText().c_str());
00299     }
00300 
00301     // Set the receive and send buffer size.
00302     if (m_status == 0)
00303     {
00304       if (!SetupComm(m_com, 0x4000, 0x4000))
00305       {
00306         m_status = GetLastError();
00307         LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> SetupComm failed (" << StatusText().c_str() << ")." << endl);
00308         //WARNINGMSG("Serial(%s): ERROR>> SetupComm failed (%s).\n", m_dev_name, StatusText().c_str());
00309       }
00310     }
00311 
00312     // Get the current serial port configuration.
00313     DCB dcb;
00314     memset(&dcb, 0, sizeof(DCB));
00315     if (m_status == 0)
00316     {
00317       if (!GetCommState(m_com, &dcb))
00318       {
00319         m_status = GetLastError();
00320         LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> GetCommState failed (" << StatusText().c_str() << ")." << endl);
00321         //WARNINGMSG("Serial(%s): ERROR>> GetCommState failed (%s).\n", m_dev_name, StatusText().c_str());
00322       }
00323     }
00324 
00325     // Set the serial port configuration from the supplied seiral flags.
00326     if (m_status == 0)
00327     {
00328       m_serial_flags.GetDCB(&dcb);
00329       if (!SetCommState(m_com, &dcb))
00330       {
00331         m_status = GetLastError();
00332         LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> SetCommState failed (" << StatusText().c_str() << ")." << endl);
00333         //WARNINGMSG("Serial(%s): ERROR>> SetCommState failed (%s).\n", m_dev_name, StatusText().c_str());
00334         return false;
00335       }
00336     }
00337   #endif
00338 
00339     return m_status==0;
00340   }
00341 
00342   void Serial::DumpData(void *data, size_t length)
00343   {
00344     unsigned char *c_data = static_cast<unsigned char *>(data);
00345     printf("Serial::DumpData: ");
00346     for (size_t i = 0; i < length; ++i)
00347     {
00348       printf("%02X ", int(c_data[i]));
00349     }
00350     printf("\n");
00351   }
00352 
00353   int Serial::ChangeBaudrate(SerialFlags::BaudRate speed)
00354   {
00355     // Nothing to be done here.
00356     if (m_serial_flags.getBaudRate()==speed)
00357       {
00358         // success
00359         return 0;
00360       }
00361     m_serial_flags.setBaudRate(speed);
00362 
00363   #if defined _SYSTEM_LINUX_
00364 
00365   # ifdef _SYSTEM_LXRT_
00366     if (is_lxrt_serial)
00367     {
00368       if (icl_core::os::IsThisLxrtTask())
00369       {
00370         // don't perform open check in lxrt, because here we open/close the device in case a different baudrate is selected!
00371         Close();
00372         Open();
00373       }
00374       else
00375       {
00376         LOGGING_DEBUG_CO(SERIAL, Serial, ChangeBaudrate, "Serial Error>> could not change baudrate of a lxrt serial in non lxrt thread." << endl);
00377       }
00378     }
00379     else
00380   # endif
00381     {
00382       if (file_descr < 0)
00383         return m_status;
00384 
00385       struct termios io_set;
00386 
00387       // Get device settings
00388       if (tcgetattr(file_descr, &io_set) < 0)
00389       {
00390         m_status = -errno;
00391         LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << "): Error>> tcgetattr failed. Status (" << m_status << ":" << strerror(-m_status) << endl);
00392         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial Error>> tcgetattr (%s) failed. m_status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00393       }
00394       else
00395       {
00396         // clear speed-settings
00397         io_set.c_cflag &= ~CBAUD;
00398         // add new speed-settings
00399         io_set.c_cflag |= SerialFlags::CFlags(speed);
00400 
00401         // set new device settings
00402         if (tcsetattr(file_descr, TCSANOW, &io_set) < 0)
00403         {
00404           m_status = -errno;
00405           LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << "): Error>> tcsetattr failed. Status (" << m_status << ":" << strerror(-m_status) << endl);
00406           //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s) Error>> tcsetattr failed. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00407         }
00408         else
00409         {
00410           LOGGING_INFO_C(SERIAL, Serial, "Serial:ChangeBaudrate " << speed << " successful." << endl);
00411           //INFOMSG("Serial:ChangeBaudrate %i successful\n", speed);
00412           m_status = 0;
00413         }
00414       }
00415     }
00416 
00417     return m_status;
00418   #endif
00419 
00420   #ifdef _SYSTEM_DARWIN_
00421     LOGGING_WARNING_C(SERIAL, Serial, "Serial:changeBaudrate() >> to be implemented" << endl);
00422     //WARNINGMSG("Serial:changeBaudrate() >> to be implemented\n");
00423     return -1;
00424   #endif
00425 
00426   #ifdef _SYSTEM_WIN32_
00427     m_status = 0;
00428 
00429     // Clears the output and input buffers.
00430     if (!PurgeComm(m_com, PURGE_RXCLEAR)
00431         || !PurgeComm(m_com, PURGE_TXCLEAR))
00432     {
00433       m_status = GetLastError();
00434       LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> PurgeComm failed (" << StatusText().c_str() << ")." << endl);
00435       //WARNINGMSG("Serial(%s): ERROR>> PurgeComm failed (%s).\n", m_dev_name, StatusText().c_str());
00436     }
00437 
00438     // Get the current serial port configuration.
00439     DCB dcb;
00440     memset(&dcb, 0, sizeof(DCB));
00441     if (m_status == 0)
00442     {
00443       if (!GetCommState(m_com, &dcb))
00444       {
00445         m_status = GetLastError();
00446         LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> GetCommState failed (" << StatusText().c_str() << ")." << endl);
00447         //WARNINGMSG("Serial(%s): ERROR>> GetCommState failed (%s).\n", m_dev_name, StatusText().c_str());
00448       }
00449     }
00450 
00451     // Set the serial port configuration with the new baud rate.
00452     if (m_status == 0)
00453     {
00454       m_serial_flags.GetDCB(&dcb);
00455       if (!SetCommState(m_com, &dcb))
00456       {
00457         m_status = GetLastError();
00458         LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> SetCommState failed (" << StatusText().c_str() << ")." << endl);
00459         //WARNINGMSG("Serial(%s): ERROR>> SetCommState failed (%s).\n", m_dev_name, StatusText().c_str());
00460       }
00461     }
00462 
00463     return -m_status;
00464   #endif
00465   }
00466 
00467   int Serial::ClearReceiveBuffer()
00468   {
00469   #ifdef _SYSTEM_WIN32_
00470     m_status = 0;
00471 
00472     // Clears the input buffers.
00473     if (PurgeComm(m_com, PURGE_RXCLEAR))
00474     {
00475       m_read_buffer_fill = 0;
00476     }
00477     else
00478     {
00479       m_status = GetLastError();
00480       LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> PurgeComm failed (" << StatusText().c_str() << ")." << endl);
00481       //WARNINGMSG("Serial(%s): ERROR>> PurgeComm failed (%s).\n", m_dev_name, StatusText().c_str());
00482     }
00483 
00484     return m_status;
00485   #elif defined _SYSTEM_LINUX_
00486     // could not test for LXRT device, so return -1 to be on the safe side
00487   # ifdef _SYSTEM_LXRT_
00488     return -1;
00489   #endif
00490     if (tcflush(file_descr, TCIFLUSH) != 0)
00491     {
00492       LOGGING_WARNING_C(SERIAL, Serial, "tcflush failed :(" << endl);
00493       return -1;
00494     }
00495   #else
00496     return -1;
00497   #endif
00498     return 0;
00499   }
00500 
00501   int Serial::ClearSendBuffer()
00502   {
00503   #ifdef _SYSTEM_WIN32_
00504     m_status = 0;
00505 
00506     // Clears the output buffers.
00507     if (PurgeComm(m_com, PURGE_TXCLEAR))
00508     {
00509       m_read_buffer_fill = 0;
00510     }
00511     else
00512     {
00513       m_status = GetLastError();
00514       LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> PurgeComm failed (" << StatusText().c_str() << ")." << endl);
00515       //WARNINGMSG("Serial(%s): ERROR>> PurgeComm failed (%s).\n", m_dev_name, StatusText().c_str());
00516     }
00517 
00518     return m_status;
00519   #elif defined _SYSTEM_LINUX_
00520     // could not test for LXRT device, so return -1 to be on the safe side
00521   # ifdef _SYSTEM_LXRT_
00522     return -1;
00523   #endif
00524     if (tcflush(file_descr, TCOFLUSH) != 0)
00525     {
00526       LOGGING_WARNING_C(SERIAL, Serial, "tcflush failed :(" << endl);
00527       return -1;
00528     }
00529   #else
00530     return -1;
00531   #endif
00532     return 0;
00533   }
00534 
00535   ssize_t Serial::Write(const void *data, ssize_t size)
00536   {
00537   #if defined _SYSTEM_LINUX_
00538     if (file_descr < 0)
00539       return m_status;
00540 
00541     int bytes_out = 0;
00542 
00543   # ifdef _SYSTEM_LXRT_
00544     if (is_lxrt_serial)
00545     {
00546       if (icl_core::os::IsThisLxrtTask())
00547       {
00548         int bytes_to_send=size;
00549         int bytes_sent=0;
00550         while (bytes_to_send>0)
00551         {
00552           int bytes_not_sent=rt_spwrite(tty, ((char*)data)+bytes_sent, bytes_to_send);
00553           if (bytes_not_sent < 0)
00554           {
00555             m_status = bytes_not_sent;
00556             LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ":" << tty << "): Error on lxrt-writing. Status (" << m_status << ":" << strerror(-m_status) << ")." << endl);
00557             //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s:%i) Error on lxrt-writing. Status (%i:%s)\n", m_dev_name, tty, m_status, strerror(-m_status));
00558             //LDM("rt_write(%i, data, %i) = failed (%i)\n", tty, bytes_to_send, bytes_not_sent);
00559             // stop it
00560             bytes_to_send = 0;
00561           }
00562           else
00563           {
00564             m_status = 0;
00565             bytes_sent += bytes_to_send - bytes_not_sent;
00566             //LDM("rt_write(%i, data, %i) = %i\n", tty, bytes_to_send, bytes_not_sent);
00567             // these bytes are left
00568             bytes_to_send = bytes_not_sent;
00569           }
00570         }
00571       }
00572       else
00573       {
00574         LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ":" << tty << "): Error>> could not write to a lxrt serial in non lxrt thread." << endl);
00575         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s:%i) Error>> could not write to a lxrt serial in non lxrt thread.\n", m_dev_name, tty);
00576       }
00577     }
00578     else
00579   # endif
00580     {
00581       // just write it to device
00582       if ((bytes_out = write(file_descr, (char*)data, size)) < 0)
00583       {
00584         m_status = -errno;
00585         LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ":" << m_dev_name << "): Error on writing. Status (" << m_status << ":" << strerror(-m_status) << ")." << endl);
00586         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s) Error on writing. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00587       }
00588       else
00589       {
00590         m_status = 0;
00591       }
00592     }
00593 
00594     return bytes_out;
00595 
00596   #elif defined _SYSTEM_WIN32_
00597 
00598     assert(m_com != INVALID_HANDLE_VALUE);
00599 
00600     DWORD bytes_written;
00601     if (!WriteFile(m_com, data, size, &bytes_written, NULL))
00602     {
00603       m_status = GetLastError();
00604       LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> could not write data (" << StatusText().c_str() << ")." << endl);
00605       //WARNINGMSG("Serial(%s): ERROR>> could not write data (%s).\n", m_dev_name, StatusText().c_str());
00606     }
00607     else
00608     {
00609       m_status = 0;
00610   #ifdef SERIAL_DUMP_DATA
00611       DumpData(data, bytes_written);
00612   #endif
00613     }
00614 
00615     return (m_status == 0 ? bytes_written : -m_status);
00616   #else
00617     return -1;
00618   #endif
00619   }
00620 
00621   ssize_t Serial::Read(void *data, ssize_t size, unsigned long time, bool return_on_less_data)
00622   {
00623     //tTime end_time = tTime().FutureUSec(time);
00624     icl_core::TimeStamp end_time = icl_core::TimeStamp::futureMSec(time / 1000);
00625 
00626   #if defined _SYSTEM_LINUX_
00627     if (file_descr < 0)
00628       return m_status;
00629 
00630     icl_core::TimeSpan tz;
00631     fd_set fds;
00632     int bytes_read  = 0;
00633     int bytes_read_inc;
00634     int select_return;
00635     char *buffer = (char*)data;
00636 
00637     if (time <= 0) time = 1;
00638     //LDM("Serial(%s)::Read(%i) (time left %li us)\n", m_dev_name, size, time);
00639 
00640     m_status = 0;
00641   # ifdef _SYSTEM_LXRT_
00642     if (is_lxrt_serial)
00643     {
00644       if (icl_core::os::IsThisLxrtTask())
00645       {
00646         int msg_size = size;
00647         RTIME timeout_relative = time;
00648         timeout_relative = nano2count(timeout_relative * 1000);
00649         int read_return;
00650         // not received the whole message, so if configured for reading on less data: read what you can get
00651         if ((read_return = rt_spread_timed(tty, (char*)data, msg_size, timeout_relative)) != 0)
00652         {
00653           //LDM("rt_spread_timed(%i, data, %i) = %i (time left %li us) => bytes read = 0\n", tty, msg_size, read_return, (end_time - icl_core::TimeStamp::now()).tsUSec());
00654           if (return_on_less_data)
00655           {
00656             read_return = rt_spread(tty, (char*)data, msg_size);
00657 
00658             if (read_return == 0)
00659             {
00660               LOGGING_ERROR_CO(SERIAL, Serial, Read, "Serial(" << m_dev_name << ")::Read(" << size << ": rt_spread_timed should have returned with data." << endl);
00661               //ERRORMSG("Serial(%s)::Read(%i): rt_spread_timed should have returned with data\n", m_dev_name, size);
00662             }
00663 
00664             if (read_return < 0)
00665             {
00666               m_status = read_return;
00667               LOGGING_DEBUG_CO(SERIAL, Serial, Read, "Error on reading " << tty " (" << m_dev_name << "). Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00668               //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Error on reading %i (%s). Status (%i:%s)\n", tty, m_dev_name, m_status, strerror(-m_status));
00669 
00670               icl_core::TimeSpan excess_read_time = icl_core::TimeStamp::now() - end_time;
00671               if (excess_read_time > icl_core::TimeSpan().fromMSec(1))
00672               {
00673                 LOGGING_ERROR_CO(SERIAL, Serial, Read, "Serial(" << m_dev_name << ")::Read(" << size << "took too long (" << excess_read_time.toUSec() << "us)" << endl);
00674                 //ERRORMSG("Serial(%s)::Read(%i) took too long (%ius)\n", m_dev_name, size, excess_read_time.ToUSec());
00675               }
00676 
00677               return m_status;
00678             }
00679             bytes_read = size - read_return;
00680             //LDM("rt_spread(%i, data, %i) = %i (time left %li us), bytes read = %i\n", tty, msg_size, read_return, (end_time - icl_core::TimeStamp::now()).tsUSec(), bytes_read);
00681           }
00682         }
00683         else
00684         {
00685           bytes_read = msg_size;
00686           //LDM("rt_spread_timed(%i, data, %i) = 0 (time left %li us) => bytes read = %i\n", tty, msg_size, (end_time - icl_core::TimeStamp::now()).tsUSec(), bytes_read);
00687         }
00688 
00689         icl_core::TimeSpan() excess_read_time = icl_core::TimeStamp::now() - end_time;
00690         if (excess_read_time > icl_core::TimeSpan().fromMSec(1))
00691         {
00692           LOGGING_ERROR_CO(SERIAL, Serial, Read, "Serial(" << m_dev_name << ")::Read(" << size << "took too long (" << excess_read_time.toUSec() << "us)" << endl);
00693           //ERRORMSG("Serial(%s)::Read(%i) took too long (%ius)\n", m_dev_name, size, excess_read_time.ToUSec());
00694         }
00695       }
00696       else
00697       {
00698         LOGGING_DEBUG_CO(SERIAL, Serial, "Serial(" << m_dev_name << ":" << tty << "). Error>> could not read from a lxrt serial in non lxrt thread." << endl);
00699         //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial(%s:%i) Error>> could not read from a lxrt serial in non lxrt thread.\n", m_dev_name, tty);
00700       }
00701     }
00702     else
00703   # endif
00704     {
00705       // We wait max time
00706       do
00707       {
00708         tz = end_time - icl_core::TimeStamp::now();
00709         // min 1 us, otherwise we will read nothing at all
00710         if (tz < icl_core::TimeSpan(0, 1000))
00711         {
00712           tz = icl_core::TimeSpan(0, 1000);
00713         }
00714 
00715         //LDM("Serial(%s) Check Read.\n", m_dev_name);
00716 
00717         FD_ZERO(&fds);
00718         FD_SET(file_descr, &fds);
00719         // Look for received data:
00720         if ((select_return = select(FD_SETSIZE, &fds, 0, 0, (timeval*) & tz)) > 0)
00721         {
00722           //LDM("Serial(%s) Select successful.\n", m_dev_name);
00723           if (return_on_less_data)
00724           {
00725             if ((bytes_read_inc = read(file_descr, &buffer[bytes_read], size - bytes_read)) < 0)
00726             {
00727               m_status = -errno;
00728               LOGGING_DEBUG_C(SERIAL, Serial, "Error on reading '" << m_dev_name << "'. Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00729               //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Error on reading '%s'. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00730               return m_status;
00731             }
00732             // Any bytes read ?
00733             if (bytes_read_inc > 0)
00734             {
00735               bytes_read += bytes_read_inc;
00736               //LDM("Serial(%s) Data read (%i => %i).\n", m_dev_name, bytes_read_inc, bytes_read);
00737               if (bytes_read == size)
00738               {
00739                 return bytes_read;
00740               }
00741             }
00742           }
00743           else
00744           {
00745             //LDM("serial:time left %lu\n",Time2Long(tz));
00746             // Are there already enough bytes received ?
00747             if (ioctl(file_descr, FIONREAD, &bytes_read_inc) < 0)
00748             {
00749               m_status = -errno;
00750               LOGGING_DEBUG_C(SERIAL, Serial, "Error on ioctl FIONREAD '" << m_dev_name << "'. Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00751               //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Error on ioctl FIONREAD '%s'. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00752               return m_status;
00753             }
00754             else
00755             {
00756               // Yes? then read data
00757               if (bytes_read_inc >= size)
00758               {
00759                 if ((bytes_read = read(file_descr, buffer, size)) < 0)
00760                 {
00761                   m_status = -errno;
00762                   LOGGING_DEBUG_C(SERIAL, Serial, "Error on read '" << m_dev_name << "'. Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00763                   //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Error on read '%s'. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00764                   return m_status;
00765                 }
00766                 else
00767                 {
00768                   //LDM("Serial(%s) Data read (%i bytes).\n", m_dev_name, bytes_read);
00769                   return bytes_read;
00770                 }
00771               }
00772               // No ? do nothing
00773             }
00774           }
00775         }
00776         else if (select_return < 0)
00777         {
00778           m_status = -errno;
00779           LOGGING_DEBUG_C(SERIAL, Serial, "Error on select '" << m_dev_name << "'. Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00780           //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Error on select '%s'. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00781           return m_status;
00782         }
00783       }
00784       // Look again for data, if any time left
00785       while (icl_core::TimeStamp::now() < end_time);
00786     }
00787 
00788     //LDM("Serial(%s)::Read(%i) (time left %li us) = %i.\n", m_dev_name, size, (end_time - icl_core::TimeStamp::now()).toUSec(), bytes_read);
00789     return bytes_read;
00790   #endif
00791 
00792 
00793   #ifdef _SYSTEM_DARWIN_
00794     LOGGING_WARNING_C(SERIAL, Serial, "Serial:Read() >> to be implemented!" << endl);
00795     //WARNINGMSG("Serial:Read() >> to be implemented\n");
00796     return 0;
00797   #endif
00798 
00799   #ifdef _SYSTEM_WIN32_
00800     assert(m_com != INVALID_HANDLE_VALUE);
00801 
00802     m_status = 0;
00803 
00804     // Set the timeout for the read operation.
00805     COMMTIMEOUTS timeout;
00806     timeout.ReadIntervalTimeout = time / 1000;
00807     timeout.ReadTotalTimeoutMultiplier = 1;
00808     timeout.ReadTotalTimeoutConstant = time / 1000;
00809     timeout.WriteTotalTimeoutMultiplier = 1;
00810     timeout.WriteTotalTimeoutConstant = MAXDWORD;
00811     if (!SetCommTimeouts(m_com, &timeout))
00812     {
00813       m_status = GetLastError();
00814       LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> setting read timeout failed (" << StatusText().c_str() << ")" << endl);
00815       //WARNINGMSG("Serial(%s): ERROR>> setting read timeout failed (%s).\n", m_dev_name, StatusText().c_str());
00816     }
00817 
00818     // Try to receive data.
00819     if (m_read_buffer_fill <= size
00820         && m_status == 0)
00821     {
00822       DWORD bytes_received = 0;
00823       size_t bytes_remaining = (m_read_buffer_fill < size ? size - m_read_buffer_fill : 0);
00824       icl_core::TimeStamp now;
00825       do
00826       {
00827         if (ReadFile(m_com, m_read_buffer + m_read_buffer_fill, bytes_remaining, &bytes_received, NULL))
00828         {
00829           m_read_buffer_fill += bytes_received;
00830           if (bytes_remaining > bytes_received)
00831           {
00832             bytes_remaining -= bytes_received;
00833           }
00834           else
00835           {
00836             bytes_remaining = 0;
00837           }
00838         }
00839         else
00840         {
00841           DWORD error = GetLastError();
00842           if (error != ERROR_TIMEOUT)
00843           {
00844             m_status = error;
00845             LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> error during read (" << StatusText().c_str() << ")" << endl);
00846             //WARNINGMSG("Serial(%s): ERROR>> error during read (%s).\n", m_dev_name, StatusText().c_str());
00847           }
00848         }
00849         now = icl_core::TimeStamp::now();
00850       }
00851       while (m_status == 0 && !return_on_less_data && bytes_remaining && now < end_time);
00852 
00853       if (m_status == 0 && !return_on_less_data && bytes_remaining && now >= end_time)
00854       {
00855         m_status = ERROR_TIMEOUT;
00856         LOGGING_WARNING_C(SERIAL, Serial, "Serial(" << m_dev_name << "): ERROR>> error during read (" << StatusText().c_str() << ")" << endl);
00857         //WARNINGMSG("Serial(%s): ERROR>> error during read (%s).\n", m_dev_name, StatusText().c_str());
00858       }
00859     }
00860 
00861     // Copy data to output buffer.
00862     ssize_t bytes_received;
00863     if (m_status == 0)
00864     {
00865       bytes_received = std::min(size, m_read_buffer_fill);
00866       memcpy(data, m_read_buffer, bytes_received);
00867 
00868       // \todo Make this more efficient.
00869       for (ssize_t write_index = 0, read_index = bytes_received; read_index < m_read_buffer_fill; ++write_index, ++read_index)
00870       {
00871         m_read_buffer[write_index] = m_read_buffer[read_index];
00872       }
00873       m_read_buffer_fill -= bytes_received;
00874 
00875   #ifdef SERIAL_DUMP_DATA
00876       DumpData(data, bytes_received);
00877   #endif
00878     }
00879 
00880     return (m_status == 0 ? bytes_received : -m_status);
00881   #endif
00882   }
00883 
00884   std::string Serial::StatusText() const
00885   {
00886   #if defined _SYSTEM_LINUX_
00887     return strerror(-m_status);
00888   #elif defined _SYSTEM_WIN32_
00889     LPVOID msg_buff = NULL;
00890     DWORD res = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
00891                               NULL,
00892                               m_status, //  from GetLastError(),
00893                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00894                               (LPTSTR) &msg_buff,
00895                               0,
00896                               NULL);
00897     std::string result;
00898     if (res)
00899     {
00900       result = (LPCTSTR)msg_buff;
00901       LocalFree(msg_buff);
00902     }
00903     else
00904     {
00905       result = "fatal internal error";
00906     }
00907     return result;
00908   #else
00909     return "Plattform not supported!";
00910   #endif
00911   }
00912 
00913   bool Serial::IsOpen() const
00914   {
00915   #ifdef _SYSTEM_LINUX_
00916     return file_descr >= 0;
00917   #elif defined _SYSTEM_WIN32_
00918     return m_com != INVALID_HANDLE_VALUE;
00919   #else
00920     return false;
00921   #endif
00922   }
00923 
00924   void Serial::Close()
00925   {
00926     //LDM("Serial::Close\n");
00927   #ifdef _SYSTEM_LINUX_
00928     if (file_descr >= 0)
00929     {
00930   # ifdef _SYSTEM_LXRT_
00931       if (is_lxrt_serial)
00932       {
00933         if (icl_core::os::IsThisLxrtTask())
00934         {
00935           //LDM("Serial lxrt close device %i\n", tty);
00936           if ((m_status = rt_spclose(tty)) < 0)
00937           {
00938             LOGGING_DEBUG_C(SERIAL, Serial, "Serial Error>> closing lxrt serial " << tty << " (" << m_dev_name << "). Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00939             //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial Error>> closing lxrt serial %i (%s). Status(%i:%s)\n", tty, m_dev_name, m_status, strerror(-m_status));
00940           }
00941         }
00942         else
00943         {
00944             LOGGING_DEBUG_C(SERIAL, Serial, "Serial Error>> could not close a lxrt serial in non lxrt thread." << endl);
00945           //DEBUGMSG(DD_SYSTEM, DL_CREATE, "Serial Error>> could not close a lxrt serial in non lxrt thread.\n");
00946         }
00947       }
00948       else
00949   # endif
00950       {
00951         // restore old setting
00952         if (tcsetattr(file_descr, TCSANOW, &io_set_old) < 0)
00953         {
00954           m_status = -errno;
00955           LOGGING_DEBUG_C(SERIAL, Serial, "Serial(" << m_dev_name << ") Error>> tcsetattr failed. Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00956           //DEBUGMSG(DD_SYSTEM, DL_CREATE, "Serial(%s) Error>> tcsetattr failed. Status (%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00957         }
00958         // close device
00959         if (close(file_descr) < 0)
00960         {
00961           m_status = -errno;
00962           LOGGING_DEBUG_C(SERIAL, Serial, "Serial>> Error closing serial " << m_dev_name << ". Status (" << m_status << ":" << strerror(-m_status) << ")" << endl);
00963           //DEBUGMSG(DD_SYSTEM, DL_CREATE, "Serial>> Error closing serial %s. Status(%i:%s)\n", m_dev_name, m_status, strerror(-m_status));
00964         }
00965       }
00966 
00967       file_descr=-1;
00968       is_lxrt_serial = false;
00969     }
00970   #endif
00971 
00972   #ifdef _SYSTEM_WIN32_
00973     if (m_com != INVALID_HANDLE_VALUE)
00974     {
00975       CloseHandle(m_com);    // close device
00976       m_com=INVALID_HANDLE_VALUE;
00977     }
00978   #endif
00979     m_status=0;
00980     //LDM("Serial::Close done.\n");
00981   }
00982 
00983   Serial::~Serial()
00984   {
00985     //LDM("~Serial start\n");
00986 
00987     Close();
00988 //    free(m_dev_name);
00989     m_dev_name = NULL;
00990 
00991     //LDM("~Serial done\n");
00992   }
00993 
00994 
00995   #ifdef _SYSTEM_LXRT_
00996   bool Serial::IsLXRTDeviceName(const char* device_name)
00997   {
00998     char *check_pointer;
00999     tty = strtol(device_name, &check_pointer, 10);
01000     if (*check_pointer == 0)
01001     {
01002       LOGGING_DEBUG_C(SERIAL, Serial,"Serial::IsLXRTDeviceName(" << m_dev_name << ") Using LXRT-serial-device " << tty << endl);
01003       //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial::IsLXRTDeviceName(%s) Using LXRT-serial-device %i\n", m_dev_name, tty);
01004       return true;
01005     }
01006     else
01007     {
01008       LOGGING_DEBUG_C(SERIAL, Serial, "Serial::IsLXRTDeviceName(" << m_dev_name << ") Using LINUX-serial-device " << tty << " (non lxrt access)" endl);
01009       //DEBUGMSG(DD_SYSTEM, DL_DEBUG, "Serial::IsLXRTDeviceName(%s) Using LINUX-serial-device %s (non lxrt access)\n", m_dev_name, m_dev_name);
01010       return false;
01011     }
01012   }
01013   #endif
01014 
01015 }
01016 }


fzi_icl_comm
Author(s):
autogenerated on Thu Jun 6 2019 21:31:31