Update of /cvsroot/playerstage/code/player/server/drivers/opaque
In directory 
sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25284/server/drivers/opaque

Added Files:
        .cvsignore Makefile.am serialstream.cc 
Log Message:
added serial stream opaque driver and modified s3000 and nav200 drivers to use 
it



--- NEW FILE: .cvsignore ---
Makefile
Makefile.in
.deps
*.la
.libs
*.lo
*.a

--- NEW FILE: serialstream.cc ---
/*
 *  Player - One Hell of a Robot Server
 *  Copyright (C) 2003
 *     Brian Gerkey
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/** @ingroup drivers Drivers */
/** @{ */
/*
 * 
The serialstream driver reads form a serial port continuously and publishes the 
data.
Currently this is usable with the SickS3000 driver and the Nav200 driver. This 
driver does
no interpretation of data output, merely reading it and publishing it, or, if 
it is sent a
data command it will write whatever it recieves onto the serial port 

@par Compile-time dependencies

- none

@par Provides

- @ref opaque

@par Requires

- none

@par Configuration requests

- PLAYER_LASER_REQ_GET_GEOM
- PLAYER_LASER_REQ_GET_CONFIG
  
@par Configuration file options

- port (string)
  - Default: "/dev/ttyS0"
  - Serial port to which laser is attached.  If you are using a
    USB/232 or USB/422 converter, this will be "/dev/ttyUSBx".

- transfer_rate (integer)
  - Rate desired for data transfers, negotiated after connection
  - Default: 38400
  - Baud rate.  Valid values are 9600, 19200, 38400, 125k, 250k, 500k

- buffer_size (integer
  - The size of the buffer to be used when reading, this is the maximum that 
can be read in one read command
  - Default 4096
      
@par Example 

@verbatim
driver
(
  name "sicks3000"
  provides ["laser:0"]
  requires ["opaque:0"]
)

driver
(
  name "serialstream"
  provides ["opaque:0]
  port "/dev/ttyS0"
)

@endverbatim

@author Toby Collett

*/
/** @} */
  

// ONLY if you need something that was #define'd as a result of configure
// (e.g., HAVE_CFMAKERAW), then #include <config.h>, like so:
/*
#if HAVE_CONFIG_H
  #include <config.h>
#endif
*/


#if HAVE_CONFIG_H
  #include <config.h>
#endif

#include <assert.h>
#include <math.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
//#include <arpa/inet.h> // for htons etc

#include <libplayercore/playercore.h>

#define DEFAULT_OPAQUE_BUFFER_SIZE 4096
#define DEFAULT_OPAQUE_PORT "/dev/ttyS0"
#define DEFAULT_OPAQUE_TRANSFER_RATE 38400

////////////////////////////////////////////////////////////////////////////////
// Device codes

#define STX     0x02
#define ACK     0xA0
#define NACK    0x92
#define CRC16_GEN_POL 0x8005

////////////////////////////////////////////////////////////////////////////////
// Error macros
#define RETURN_ERROR(erc, m) {PLAYER_ERROR(m); return erc;}

////////////////////////////////////////////////////////////////////////////////
// The class for the driver
class SerialStream : public Driver
{
  public:

    // Constructor; need that
    SerialStream(ConfigFile* cf, int section);
    virtual ~SerialStream();

    // Must implement the following methods.
    virtual int Setup();
    virtual int Shutdown();
    
    // This method will be invoked on each incoming message
    virtual int ProcessMessage(QueuePointer &resp_queue,
                               player_msghdr * hdr,
                               void * data);

  private:

    // Main function for device thread.
    virtual void Main();

    // Update the data
    virtual void ReadData();

    // Open the terminal
    // Returns 0 on success
    virtual int OpenTerm();

    // Close the terminal
    // Returns 0 on success
    virtual int CloseTerm();
    
    // Set the terminal speed
    // Valid values are 9600, 19200, 38400, 115200
    // Returns 0 on success
    virtual int ChangeTermSpeed(int speed);
    
  protected:
    //int transfer_rate; // Desired rate for operation
    int current_rate;
    
    // Name of device used to communicate with the laser
    //const char *device_name;
    
    uint8_t * rx_buffer;
    //unsigned int rx_buffer_size;
    
    struct termios oldtio;
    
    // opaque device file descriptor
    int opaque_fd; 
    
    // Properties
    IntProperty buffer_size, transfer_rate;
    StringProperty port;
    
    // This is the data we store and send
    player_opaque_data_t mData;

};

// A factory creation function, declared outside of the class so that it
// can be invoked without any object context (alternatively, you can
// declare it static in the class).  In this function, we create and return
// (as a generic Driver*) a pointer to a new instance of this driver.
Driver*
SerialStream_Init(ConfigFile* cf, int section)
{
  // Create and return a new instance of this driver
  return((Driver*)(new SerialStream(cf, section)));
}

// A driver registration function, again declared outside of the class so
// that it can be invoked without object context.  In this function, we add
// the driver into the given driver table, indicating which interface the
// driver can support and how to create a driver instance.
void SerialStream_Register(DriverTable* table)
{
  table->AddDriver("serialstream", SerialStream_Init);
}

////////////////////////////////////////////////////////////////////////////////
// Constructor.  Retrieve options from the configuration file and do any
// pre-Setup() setup.
SerialStream::SerialStream(ConfigFile* cf, int section)
    : Driver(cf, section, false, PLAYER_MSGQUEUE_DEFAULT_MAXLEN,
             PLAYER_OPAQUE_CODE),
             buffer_size ("buffer_size", DEFAULT_OPAQUE_BUFFER_SIZE, 0), port 
("port", DEFAULT_OPAQUE_PORT, 0), transfer_rate ("transfer_rate", 
DEFAULT_OPAQUE_TRANSFER_RATE, 0)
{
          this->RegisterProperty ("buffer_size", &this->buffer_size, cf, 
section);
          this->RegisterProperty ("port", &this->port, cf, section);
          this->RegisterProperty ("transfer_rate", &this->transfer_rate, cf, 
section);
        
          rx_buffer = new uint8_t[buffer_size];
          assert(rx_buffer);

          this->current_rate = 0;

          return;
}

SerialStream::~SerialStream()
{
        delete [] rx_buffer;
}

////////////////////////////////////////////////////////////////////////////////
// Set up the device.  Return 0 if things go well, and -1 otherwise.
int SerialStream::Setup()
{
        PLAYER_MSG1(2, "Opaque Driver initialising (%s)", port.GetValue());

        // Open the terminal
        if (OpenTerm())
            return -1;

        PLAYER_MSG0(2, "Opaque Driver ready");

  // Start the device thread; spawns a new thread and executes
  // SerialStream::Main(), which contains the main loop for the driver.
  StartThread();

  return(0);
}


////////////////////////////////////////////////////////////////////////////////
// Shutdown the device
int SerialStream::Shutdown()
{
  // Stop and join the driver thread
  StopThread();
  
  CloseTerm();

  PLAYER_MSG0(2, "Opaque Driver Shutdown");

  return(0);
}

int SerialStream::ProcessMessage(QueuePointer & resp_queue,
                                 player_msghdr* hdr,
                                 void* data)
{  
        // Process messages here.  Send a response if necessary, using 
Publish().
        // If you handle the message successfully, return 0.  Otherwise,
        // return -1, and a NACK will be sent for you, if a response is 
required.
        int res;
        // Check for properties
        if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_REQ, 
PLAYER_SET_INTPROP_REQ, this->device_addr))
        {
            player_intprop_req_t req = *reinterpret_cast<player_intprop_req_t*> 
(data);
            PLAYER_MSG1(2, "%s", req.key);
            if (strcmp("transfer_rate", req.key))
            {
                //puts("Message recieved");
                res = ChangeTermSpeed(req.value);           
           
                        // Check the error code
                        if (res == 0)
                        {
                          transfer_rate.SetValueFromMessage 
(reinterpret_cast<void*> (&req));
                          Publish(this->device_addr, resp_queue, 
PLAYER_MSGTYPE_RESP_ACK, PLAYER_SET_INTPROP_REQ, NULL, 0, NULL);
                        }
                        else
                        {
                          Publish(this->device_addr, resp_queue, 
PLAYER_MSGTYPE_RESP_NACK, PLAYER_SET_INTPROP_REQ, NULL, 0, NULL);
                        }
                        return (0);
            }
        }
        //else if it is a opaque data message then I want to flush the current 
serial port and write to whatever is connected to the serial port
        else if (Message::MatchMessage (hdr, PLAYER_MSGTYPE_CMD, 
PLAYER_OPAQUE_CMD_DATA, this->device_addr))
        {
                PLAYER_MSG0(2, "Command message received");
            player_opaque_data_t * recv = reinterpret_cast<player_opaque_data_t 
* > (data);
            // Make sure both input and output queues are empty
            tcflush(opaque_fd, TCIOFLUSH);

            // switch to blocking IO for the write
            int flags = fcntl(opaque_fd, F_GETFL);
            if (flags < 0 || fcntl(opaque_fd,F_SETFL,flags &~O_NONBLOCK) < 0)
            {
              fprintf(stderr,"Error changing to blocking write (%d - %s), 
disabling\n",errno,strerror(errno));
              return -1;
            }

            if((recv->data_count && (write(opaque_fd, recv->data, 
recv->data_count)) < recv->data_count))
            {
              fprintf(stderr,"Error writing to FOB (%d - %s), 
disabling\n",errno,strerror(errno));
              return -1;
            }

            // restore flags
            if (fcntl(opaque_fd,F_SETFL,flags) < 0)
            {
              fprintf(stderr,"Error restoring file mode (%d - %s), 
disabling\n",errno,strerror(errno));
            }
            
            return (0);
        }

        return(-1);
}



////////////////////////////////////////////////////////////////////////////////
// Main function for device thread
void SerialStream::Main()
{
  // The main loop; interact with the device here
  for(;;)
  {
    // test if we are supposed to cancel
    pthread_testcancel();

    // Process incoming messages.  SerialStream::ProcessMessage() is
    // called on each message.
    ProcessMessages();

    // Reads the data from the serial port and then publishes it
    ReadData();

    // Sleep (you might, for example, block on a read() instead)
    usleep(100000);
  }
}

////////////////////////////////////////////////////////////////////////////////
// Open the terminal
// Returns 0 on success
int SerialStream::OpenTerm()
{
  //this->opaque_fd = ::open(/*this->device_name*/ port, O_RDWR | O_SYNC , 
S_IRUSR | S_IWUSR );
  this->opaque_fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
  if (this->opaque_fd < 0)
  {
    PLAYER_ERROR2("unable to open serial port [%s]; [%s]",
                    port.GetValue(), strerror(errno));
    return -1;
  }
   
  // save the current io settings
  tcgetattr(opaque_fd, &oldtio);
  
  // set up new settings
  struct termios newtio;
  memset(&newtio, 0,sizeof(newtio));
  newtio.c_cflag = CS8 | CREAD | PARENB;
  newtio.c_iflag = INPCK;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  
  tcsetattr(opaque_fd, TCSANOW, &newtio);
  tcflush(opaque_fd, TCIOFLUSH);
  puts("about to change term speed");
  if (ChangeTermSpeed(transfer_rate))
            return -1;
  
  puts("about to fluch");
  // Make sure queue is empty
  //
  tcflush(this->opaque_fd, TCIOFLUSH);
  usleep(1000);
  tcflush(opaque_fd, TCIFLUSH);
   
  puts("finished opening term");
  
  return 0;
}


////////////////////////////////////////////////////////////////////////////////
// Set the terminal speed
// Valid values are 9600, 19200, 38400, 115200
// Returns 0 on success
//
int SerialStream::ChangeTermSpeed(int speed)
{
  struct termios term;

  current_rate = speed;

  int term_speed;
  switch(speed)
  {
    case 9600:
                term_speed = B9600;
                break;
        case 19200:
                term_speed = B19200;
                break;
        case 38400:
                term_speed = B38400;
                break;
        case 115200:
                term_speed = B115200;
                break;
        default:
                term_speed = speed;
  }

  switch(term_speed)
  {
    case B9600:
    case B19200:
    case B38400:
    case B115200:
      if( tcgetattr( this->opaque_fd, &term ) < 0 )
        RETURN_ERROR(1, "unable to get device attributes");
        
      //cfmakeraw( &term );
          if(cfsetispeed( &term, term_speed ) < 0 || cfsetospeed( &term, 
term_speed ) < 0)
          {
                  RETURN_ERROR(1, "failed to set serial baud rate");
          }
        
      if( tcsetattr( this->opaque_fd, TCSAFLUSH, &term ) < 0 )
        RETURN_ERROR(1, "unable to set device attributes");
      break;
      PLAYER_MSG0(2, "Communication rate changed");

    default:
      PLAYER_ERROR1("unknown speed %d", speed);
      return 1;
  }
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
// Close the terminal
// Returns 0 on success
//
int SerialStream::CloseTerm()
{
  ::close(this->opaque_fd);
  return 0;
}

////////////////////////////////////////////////////////////////////////////////
// Read range data from laser
//
void SerialStream::ReadData()
{
  // Read a packet from the laser
  //
  int len = read(this->opaque_fd, rx_buffer, /*rx_buffer_size*/ buffer_size);
  if (len == 0)
  {
   // PLAYER_MSG0(2, "empty packet");
    return;
  }

  if (len < 0)
  {
    PLAYER_ERROR2("error reading form serial port: %d %s", errno, 
strerror(errno));
    return;
  }

  assert(len <  int(buffer_size));
  mData.data_count = len;
  mData.data = rx_buffer;
  int fd = open("/home/inro/myopaque/temp" , O_RDWR | O_NOCTTY | O_NDELAY | 
O_NONBLOCK);
  Publish(this->device_addr, PLAYER_MSGTYPE_DATA, PLAYER_OPAQUE_DATA_STATE, 
reinterpret_cast<void*>(&mData));
}

--- NEW FILE: Makefile.am ---
noinst_LTLIBRARIES = 
if INCLUDE_SERIALSTREAM
noinst_LTLIBRARIES += libserialstream.la
endif

AM_CPPFLAGS = -Wall -I$(top_srcdir)

libserialstream_la_SOURCES = serialstream.cc




-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell.  From the desktop to the data center, Linux is going
mainstream.  Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit

Reply via email to