topical media & game development

talk show tell print

lib-of-vs-libs-openFrameworks-communication-ofSerial.cpp / cpp



  include <ofSerial.h>
  include <ofMain.h>
  
  //---------------------------------------------
  ifdef TARGET_WIN32
  //---------------------------------------------
  
  //------------------------------------
     // needed for serial bus enumeration:
     //4d36e978-e325-11ce-bfc1-08002be10318}
     DEFINE_GUID (GUID_SERENUM_BUS_ENUMERATOR, 0x4D36E978, 0xE325,
     0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18);
  //------------------------------------
  
  void ofSerial::enumerateWin32Ports(){
  
      // thanks joerg for fixes...
  
          if (bPortsEnumerated == true) return;
  
          HDEVINFO hDevInfo = NULL;
          SP_DEVINFO_DATA DeviceInterfaceData;
          int i = 0;
          DWORD dataType, actualSize = 0;
          unsigned char dataBuf[MAX_PATH + 1];
  
          // Reset Port List
          nPorts = 0;
          // Search device set
          hDevInfo = SetupDiGetClassDevs((struct _GUID *)&GUID_SERENUM_BUS_ENUMERATOR,0,0,DIGCF_PRESENT);
          if ( hDevInfo ){
        while (TRUE){
           ZeroMemory(&DeviceInterfaceData, sizeof(DeviceInterfaceData));
           DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
           if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInterfaceData)){
               // SetupDiEnumDeviceInfo failed
               break;
           }
  
           if (SetupDiGetDeviceRegistryProperty(hDevInfo,
               &DeviceInterfaceData,
               SPDRP_FRIENDLYNAME,
               &dataType,
               dataBuf,
               sizeof(dataBuf),
               &actualSize)){
  
                          sprintf(portNamesFriendly[nPorts], "\%s", dataBuf);
                          portNamesShort[nPorts][0] = 0;
  
                          // turn blahblahblah(COM4) into COM4
  
              char *   begin    = NULL;
              char *   end    = NULL;
              begin          = strstr((char *)dataBuf, "COM");
  
              if (begin)
                  {
                  end          = strstr(begin, ")");
                  if (end)
                      {
                        *end = 0;   // get rid of the )...
                        strcpy(portNamesShort[nPorts], begin);
                  }
                  if (nPorts++ > MAX_SERIAL_PORTS)
                          break;
              }
           }
              i++;
        }
     }
     SetupDiDestroyDeviceInfoList(hDevInfo);
  
     bPortsEnumerated = false;
  }
  
  //---------------------------------------------
  endif
  //---------------------------------------------
  
  //----------------------------------------------------------------
  ofSerial::ofSerial(){
  
          //---------------------------------------------
          #ifdef TARGET_WIN32
          //---------------------------------------------
                  nPorts                                 = 0;
                  bPortsEnumerated         = false;
  
                  portNamesShort = new char * [MAX_SERIAL_PORTS];
                  portNamesFriendly = new char * [MAX_SERIAL_PORTS];
                  for (int i = 0; i < MAX_SERIAL_PORTS; i++){
                          portNamesShort[i] = new char[10];
                          portNamesFriendly[i] = new char[MAX_PATH];
                  }
          //---------------------------------------------
          #endif
          //---------------------------------------------
          bVerbose = false;
  }
  
  //----------------------------------------------------------------
  ofSerial::~ofSerial(){
  
          close();
  
          //---------------------------------------------
          #ifdef TARGET_WIN32
          //---------------------------------------------
                  nPorts                                 = 0;
                  bPortsEnumerated         = false;
  
                  for (int i = 0; i < MAX_SERIAL_PORTS; i++) {
                          delete [] portNamesShort[i];
                          delete [] portNamesFriendly[i];
                  }
                  delete [] portNamesShort;
                  delete [] portNamesFriendly;
  
          //---------------------------------------------
          #endif
          //---------------------------------------------
  
          bVerbose = false;
          bInited = false;
  }
  
  //----------------------------------------------------------------
  void ofSerial::enumerateDevices(){
  
          //---------------------------------------------
          #if defined( TARGET_OSX )
          //---------------------------------------------
  
                  //----------------------------------------------------
                  //We will find serial devices by listing the directory
  
                  DIR *dir;
                  struct dirent *entry;
                  dir = opendir("/dev");
                  string str                        = "";
                  string device                = "";
                  int deviceCount                = 0;
  
                  if (dir == NULL){
                          ofLog(OF_LOG_ERROR,"ofSerial: error listing devices in /dev");
                  } else {
                          ofLog(OF_LOG_NOTICE,"ofSerial: listing devices");
                          while ((entry = readdir(dir)) != NULL){
                                  str = (char *)entry->d_name;
                                  if( str.substr(0,3) == "cu." ){
                                          ofLog(OF_LOG_NOTICE,"device \%i - \%s", deviceCount, str.c_str());
                                          deviceCount++;
                                  }
                          }
                  }
  
          //---------------------------------------------
      #endif
      //---------------------------------------------
  
          //---------------------------------------------
          #if defined( TARGET_LINUX )
          //---------------------------------------------
  
                  //----------------------------------------------------
                  //We will find serial devices by listing the directory
  
                  DIR *dir;
                  struct dirent *entry;
                  dir = opendir("/dev");
                  string str                        = "";
                  string device                = "";
                  int deviceCount                = 0;
  
                  if (dir == NULL){
                          ofLog(OF_LOG_ERROR,"ofSerial: error listing devices in /dev");
                  } else {
                          ofLog(OF_LOG_NOTICE,"ofSerial: listing devices");
                          while ((entry = readdir(dir)) != NULL){
                                  str = (char *)entry->d_name;
                                  if( str.substr(0,3) == "tty" || str.substr(0,3) == "rfc" ){
                                          ofLog(OF_LOG_NOTICE,"device \%i - \%s", deviceCount, str.c_str());
                                          deviceCount++;
                                  }
                          }
                  }
  
          //---------------------------------------------
          #endif
          //---------------------------------------------
  
          //---------------------------------------------
          #ifdef TARGET_WIN32
          //---------------------------------------------
  
                  enumerateWin32Ports();
                  ofLog(OF_LOG_NOTICE,"ofSerial: listing devices (\%i total)\n", nPorts);
                  for (int i = 0; i < nPorts; i++){
                          ofLog(OF_LOG_ERROR,"device \%i -- \%s", i, portNamesFriendly[i]);
                  }
  
          //---------------------------------------------
      #endif
      //---------------------------------------------
  
  }
  
  //----------------------------------------------------------------
  void ofSerial::close(){
  
          //---------------------------------------------
          #ifdef TARGET_WIN32
          //---------------------------------------------
                  if (bInited){
                          SetCommTimeouts(hComm,&oldTimeout);
                          CloseHandle(hComm);
                          hComm                 = INVALID_HANDLE_VALUE;
                          bInited         = false;
                  }
          //---------------------------------------------
      #else
      //---------------------------------------------
              if (bInited){
                      tcsetattr(fd,TCSANOW,&oldoptions);
                      ::close(fd);
              }
              // [CHECK] -- anything else need to be reset?
      //---------------------------------------------
      #endif
      //---------------------------------------------
  
  }
  
  //----------------------------------------------------------------
  bool ofSerial::setup(){
          return setup(0,9600);                // the first one, at 9600 is a good choice...
  }
  
  //----------------------------------------------------------------
  bool ofSerial::setup(int deviceNumber, int baud){
  
          int deviceCount = 0;
  
          string str                        = "";
          string device                = "";
          bool deviceFound        = false;
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
          //---------------------------------------------
  
                  //----------------------------------------------------
                  //We will find serial devices by listing the directory
  
                  DIR *dir;
                  struct dirent *entry;
                  dir = opendir("/dev");
  
                  if (dir == NULL){
                          ofLog(OF_LOG_ERROR,"ofSerial: error listing devices in /dev");
                  }
  
                  while ((entry = readdir(dir)) != NULL){
                          str = (char *)entry->d_name;
                          if( str.substr(0,3) == "cu." ){
                                  if(deviceCount == deviceNumber){
                                          device = "/dev/"+str;
                                          deviceFound = true;
                                          ofLog(OF_LOG_NOTICE,"ofSerial device \%i - /dev/\%s  <--selected", deviceCount, str.c_str());
                                  }else ofLog(OF_LOG_NOTICE,"ofSerial device \%i - /dev/\%s", deviceCount, str.c_str());
                                  deviceCount++;
                          }
                  }
  
          if(deviceFound){
              return setup(device, baud);
          }else{
              ofLog(OF_LOG_ERROR,"ofSerial: could not find device \%i - only \%i devices found", deviceNumber, deviceCount);
              return false;
          }
  
          //---------------------------------------------
      #endif
      //---------------------------------------------
  
          //---------------------------------------------
          #ifdef TARGET_WIN32
          //---------------------------------------------
  
                  enumerateWin32Ports();
                  if (deviceNumber < nPorts){
                          device = portNamesShort[deviceNumber];
                          deviceFound = true;
                  }
  
          if(deviceFound){
              return setup(device, baud);
          }else{
              ofLog(OF_LOG_ERROR,"ofSerial: could not find device \%i - only \%i devices found", deviceNumber, nPorts);
              return false;
          }
  
          //---------------------------------------------
      #endif
      //---------------------------------------------
  
  }
  
  //----------------------------------------------------------------
  bool ofSerial::setup(string portName, int baud){
  
          bInited = false;
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
          //---------------------------------------------
  
              ofLog(OF_LOG_NOTICE,"ofSerialInit: opening port \%s @ \%d bps", portName.c_str(), baud);
                  fd = open(portName.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK);
                  if(fd == -1){
                          ofLog(OF_LOG_ERROR,"ofSerial: unable to open port");
                          return false;
                  }
  
                  struct termios options;
                  tcgetattr(fd,&oldoptions);
                  options = oldoptions;
                  switch(baud){
                     case 300:         cfsetispeed(&options,B300);
                                                  cfsetospeed(&options,B300);
                                                  break;
                     case 1200:         cfsetispeed(&options,B1200);
                                                  cfsetospeed(&options,B1200);
                                                  break;
                     case 2400:         cfsetispeed(&options,B2400);
                                                  cfsetospeed(&options,B2400);
                                                  break;
                     case 4800:         cfsetispeed(&options,B4800);
                                                  cfsetospeed(&options,B4800);
                                                  break;
                     case 9600:         cfsetispeed(&options,B9600);
                                                  cfsetospeed(&options,B9600);
                                                  break;
                     case 14400:         cfsetispeed(&options,B14400);
                                                  cfsetospeed(&options,B14400);
                                                  break;
                     case 19200:         cfsetispeed(&options,B19200);
                                                  cfsetospeed(&options,B19200);
                                                  break;
                     case 28800:         cfsetispeed(&options,B28800);
                                                  cfsetospeed(&options,B28800);
                                                  break;
                     case 38400:         cfsetispeed(&options,B38400);
                                                  cfsetospeed(&options,B38400);
                                                  break;
                     case 57600:  cfsetispeed(&options,B57600);
                                                  cfsetospeed(&options,B57600);
                                                  break;
                     case 115200: cfsetispeed(&options,B115200);
                                                  cfsetospeed(&options,B115200);
                                                  break;
  
                          default:        cfsetispeed(&options,B9600);
                                                  cfsetospeed(&options,B9600);
                                                  ofLog(OF_LOG_ERROR,"ofSerialInit: cannot set \%i baud setting baud to 9600\n", baud);
                                                  break;
                  }
  
                  options.c_cflag |= (CLOCAL | CREAD);
                  options.c_cflag &= ~PARENB;
                  options.c_cflag &= ~CSTOPB;
                  options.c_cflag &= ~CSIZE;
                  options.c_cflag |= CS8;
                  tcsetattr(fd,TCSANOW,&options);
  
                  bInited = true;
                  ofLog(OF_LOG_NOTICE,"sucess in opening serial connection");
  
              return true;
          //---------------------------------------------
      #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
          //---------------------------------------------
  
          // open the serial port:
          // "COM4", etc...
  
          hComm=CreateFileA(portName.c_str(),GENERIC_READ|GENERIC_WRITE,0,0,
                                          OPEN_EXISTING,0,0);
  
          if(hComm==INVALID_HANDLE_VALUE){
                  ofLog(OF_LOG_ERROR,"ofSerial: unable to open port");
                  return false;
          }
  
          // now try the settings:
          COMMCONFIG cfg;
          DWORD cfgSize;
          char  buf[80];
  
          cfgSize=sizeof(cfg);
          GetCommConfig(hComm,&cfg,&cfgSize);
          int bps = baud;
          sprintf(buf,"baud=\%d parity=N data=8 stop=1",bps);
  
          #if (_MSC_VER)       // microsoft visual studio
                  // msvc doesn't like BuildCommDCB,
                  //so we need to use this version: BuildCommDCBA
                  if(!BuildCommDCBA(buf,&cfg.dcb)){
                          ofLog(OF_LOG_ERROR,"ofSerial: unable to build comm dcb; (\%s)",buf);
                  }
          #else
                  if(!BuildCommDCB(buf,&cfg.dcb)){
                          ofLog(OF_LOG_ERROR,"ofSerial: Can't build comm dcb; \%s",buf);
                  }
          #endif
  
          // Set baudrate and bits etc.
          // Note that BuildCommDCB() clears XON/XOFF and hardware control by default
  
          if(!SetCommState(hComm,&cfg.dcb)){
                  ofLog(OF_LOG_ERROR,"ofSerial: Can't set comm state");
          }
          //ofLog(OF_LOG_NOTICE,buf,"bps=\%d, xio=\%d/\%d",cfg.dcb.BaudRate,cfg.dcb.fOutX,cfg.dcb.fInX);
  
          // Set communication timeouts (NT)
          COMMTIMEOUTS tOut;
          GetCommTimeouts(hComm,&oldTimeout);
          tOut = oldTimeout;
          // Make timeout so that:
          // - return immediately with buffered characters
          tOut.ReadIntervalTimeout=MAXDWORD;
          tOut.ReadTotalTimeoutMultiplier=0;
          tOut.ReadTotalTimeoutConstant=0;
          SetCommTimeouts(hComm,&tOut);
  
          bInited = true;
          return true;
          //---------------------------------------------
          #endif
          //---------------------------------------------
  }
  
  //----------------------------------------------------------------
  int ofSerial::writeBytes(unsigned char * buffer, int length){
  
          if (!bInited){
                  ofLog(OF_LOG_ERROR,"ofSerial: serial not inited");
                  return OF_SERIAL_ERROR;
          }
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
              int numWritten = write(fd, buffer, length);
                  if(numWritten <= 0){
                          ofLog(OF_LOG_ERROR,"ofSerial: Can't write to com port");
                          return OF_SERIAL_ERROR;
                  }
  
                  ofLog(OF_LOG_VERBOSE,"ofSerial: numWritten \%i", numWritten);
  
              return numWritten;
      #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
                  DWORD written;
                  if(!WriteFile(hComm, buffer, length, &written,0)){
                           ofLog(OF_LOG_ERROR,"ofSerial: Can't write to com port");
                           return OF_SERIAL_ERROR;
                  }
                  ofLog(OF_LOG_VERBOSE,"ofSerial: numWritten \%i", (int)written);
                  return (int)written;
          #endif
          //---------------------------------------------
  
  }
  
  //----------------------------------------------------------------
  int ofSerial::readBytes(unsigned char * buffer, int length){
  
          if (!bInited){
                  ofLog(OF_LOG_ERROR,"ofSerial: serial not inited");
                  return OF_SERIAL_ERROR;
          }
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
                  int nRead = read(fd, buffer, length);
                  if(nRead < 0){
                          ofLog(OF_LOG_ERROR,"ofSerial: trouble reading from port");
                          return OF_SERIAL_ERROR;
                  }
                  return nRead;
      #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
                  DWORD nRead = 0;
                  if (!ReadFile(hComm,buffer,length,&nRead,0)){
                          ofLog(OF_LOG_ERROR,"ofSerial: trouble reading from port");
                          return OF_SERIAL_ERROR;
                  }
                  return (int)nRead;
          #endif
          //---------------------------------------------
  }
  
  //----------------------------------------------------------------
  bool ofSerial::writeByte(unsigned char singleByte){
  
          if (!bInited){
                  ofLog(OF_LOG_ERROR,"ofSerial: serial not inited");
                  return OF_SERIAL_ERROR;
          }
  
          unsigned char tmpByte[1];
          tmpByte[0] = singleByte;
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
              int numWritten = 0;
              numWritten = write(fd, tmpByte, 1);
                  if(numWritten <= 0 ){
                           ofLog(OF_LOG_ERROR,"ofSerial: Can't write to com port");
                           return OF_SERIAL_ERROR;
                  }
                  ofLog(OF_LOG_VERBOSE,"ofSerial: written byte");
  
                  return (numWritten > 0 ? true : false);
      #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
                  DWORD written = 0;
                  if(!WriteFile(hComm, tmpByte, 1, &written,0)){
                           ofLog(OF_LOG_ERROR,"ofSerial: Can't write to com port");
                           return OF_SERIAL_ERROR;;
                  }
  
                  ofLog(OF_LOG_VERBOSE,"ofSerial: written byte");
  
                  return ((int)written > 0 ? true : false);
          #endif
          //---------------------------------------------
  
  }
  
  //----------------------------------------------------------------
  int ofSerial::readByte(){
  
          if (!bInited){
                  ofLog(OF_LOG_ERROR,"ofSerial: serial not inited");
                  return OF_SERIAL_ERROR;
          }
  
          unsigned char tmpByte[1];
          memset(tmpByte, 0, 1);
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
                  int nRead = read(fd, tmpByte, 1);
                  if(nRead < 0){
                          ofLog(OF_LOG_ERROR,"ofSerial: trouble reading from port");
              return OF_SERIAL_ERROR;
                  }
                  if(nRead == 0)
                          return OF_SERIAL_NO_DATA;
      #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
                  DWORD nRead;
                  if (!ReadFile(hComm, tmpByte, 1, &nRead, 0)){
                          ofLog(OF_LOG_ERROR,"ofSerial: trouble reading from port");
                          return OF_SERIAL_ERROR;
                  }
          #endif
          //---------------------------------------------
  
          return (int)(tmpByte[0]);
  }
  
  //----------------------------------------------------------------
  void ofSerial::flush(bool flushIn, bool flushOut){
  
          if (!bInited){
                  ofLog(OF_LOG_ERROR,"ofSerial: serial not inited");
                  return;
          }
  
          int flushType = 0;
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
                  if( flushIn && flushOut) flushType = TCIOFLUSH;
                  else if(flushIn) flushType = TCIFLUSH;
                  else if(flushOut) flushType = TCOFLUSH;
                  else return;
  
                  tcflush(fd, flushType);
      #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
                  if( flushIn && flushOut) flushType = PURGE_TXCLEAR | PURGE_RXCLEAR;
                  else if(flushIn) flushType = PURGE_RXCLEAR;
                  else if(flushOut) flushType = PURGE_TXCLEAR;
                  else return;
  
                  PurgeComm(hComm, flushType);
          #endif
          //---------------------------------------------
  
  }
  
  //-------------------------------------------------------------
  int ofSerial::available(){
  
          if (!bInited){
                  ofLog(OF_LOG_ERROR,"ofSerial: serial not inited");
                  return OF_SERIAL_ERROR;
          }
  
          int numBytes = 0;
  
          //---------------------------------------------
          #if defined( TARGET_OSX ) || defined( TARGET_LINUX )
                  ioctl(fd,FIONREAD,&numBytes);
          #endif
      //---------------------------------------------
  
      //---------------------------------------------
          #ifdef TARGET_WIN32
          COMSTAT stat;
                 DWORD err;
                 if(hComm!=INVALID_HANDLE_VALUE){
             if(!ClearCommError(hComm, &err, &stat)){
                 numBytes = 0;
             } else {
                 numBytes = stat.cbInQue;
             }
                 } else {
             numBytes = 0;
                 }
          #endif
      //---------------------------------------------
  
          return numBytes;
  }
  
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.