Revision: 8819
          http://playerstage.svn.sourceforge.net/playerstage/?rev=8819&view=rev
Author:   jpgr87
Date:     2010-07-08 03:21:37 +0000 (Thu, 08 Jul 2010)

Log Message:
-----------
Applied patch #2948822: hemisson driver

Modified Paths:
--------------
    code/player/trunk/server/drivers/mixed/CMakeLists.txt

Added Paths:
-----------
    code/player/trunk/server/drivers/mixed/hemisson/
    code/player/trunk/server/drivers/mixed/hemisson/CMakeLists.txt
    code/player/trunk/server/drivers/mixed/hemisson/hemisson.cc
    code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.cc
    code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.h

Modified: code/player/trunk/server/drivers/mixed/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/mixed/CMakeLists.txt       2010-07-08 
02:56:35 UTC (rev 8818)
+++ code/player/trunk/server/drivers/mixed/CMakeLists.txt       2010-07-08 
03:21:37 UTC (rev 8819)
@@ -6,6 +6,7 @@
 ADD_SUBDIRECTORY (erratic)
 ADD_SUBDIRECTORY (evolution)
 ADD_SUBDIRECTORY (garcia)
+ADD_SUBDIRECTORY (hemisson)
 ADD_SUBDIRECTORY (irobot)
 ADD_SUBDIRECTORY (khepera)
 ADD_SUBDIRECTORY (mricp)

Added: code/player/trunk/server/drivers/mixed/hemisson/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/mixed/hemisson/CMakeLists.txt              
                (rev 0)
+++ code/player/trunk/server/drivers/mixed/hemisson/CMakeLists.txt      
2010-07-08 03:21:37 UTC (rev 8819)
@@ -0,0 +1,7 @@
+PLAYERDRIVER_OPTION (hemisson build_hemisson ON)
+PLAYERDRIVER_REJECT_OS (hemisson build_hemisson PLAYER_OS_WIN)
+PLAYERDRIVER_REQUIRE_HEADER (hemisson build_hemisson sys/ioctl.h sys/types.h)
+PLAYERDRIVER_REQUIRE_HEADER (hemisson build_hemisson sys/stat.h sys/types.h)
+PLAYERDRIVER_REQUIRE_HEADER (hemisson build_hemisson sys/time.h sys/types.h)
+PLAYERDRIVER_REQUIRE_HEADER (hemisson build_hemisson sys/select.h sys/types.h)
+PLAYERDRIVER_ADD_DRIVER (hemisson build_hemisson SOURCES hemisson.cc 
hemisson_serial.cc)

Added: code/player/trunk/server/drivers/mixed/hemisson/hemisson.cc
===================================================================
--- code/player/trunk/server/drivers/mixed/hemisson/hemisson.cc                 
        (rev 0)
+++ code/player/trunk/server/drivers/mixed/hemisson/hemisson.cc 2010-07-08 
03:21:37 UTC (rev 8819)
@@ -0,0 +1,481 @@
+/*
+ *  Player - One Hell of a Robot Server
+ *  Copyright (C) 2000
+ *     Brian Gerkey, Kasper Stoy, Richard Vaughan, & Andrew Howard
+ *
+ *
+ *  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
+ *
+ */
+
+/* Copyright (C) 2010
+ *   Paul Osmialowski
+ * Copyright (C) 2004
+ *   Toby Collett, University of Auckland Robotics Group
+ */
+
+/** @ingroup drivers */
+/** @{ */
+/** @defgroup driver_hemisson hemisson
+ * @brief K-Team Hemisson mobile robot
+
+The hemisson driver is used to interface to the K-Team hemisson robot.
+
+This driver is experimental and should be treated with caution. At
+this point it supports the @ref interface_position2d and
+...@ref interface_ranger interfaces.
+
+This driver was tested with RS-232C cable link (for example /dev/ttyS0)
+and bluetooth radio link (/dev/rfcomm0 or /dev/ttyUB0).
+
+...@par Compile-time dependencies
+
+- none
+
+...@par Provides
+
+- @ref interface_position2d
+- @ref interface_ranger
+
+...@par Requires
+
+- none
+
+...@par Configuration file options
+
+- port (string)
+  - Default: "/dev/rfcomm0"
+  - Serial port used to communicate with the robot.
+- sleep_nsec (integer)
+  - Default: 100000000
+  - timespec value for nanosleep().
+- init_motor_state (integer)
+  - Default: 0
+  - Initial motor state.
+- speed_factor (float)
+  - Default: 18.0
+  - Speed scale factor.
+- aspeed_factor (float)
+  - Default: 16.0
+  - Angular speed scale factor.
+- publish_ranges (integer)
+  - Default: 8
+  - Vaild values: 1..8
+  - Number of ranger scans to publish.
+- set_stall (integer)
+  - Default: 0
+  - If set to non-zero, stall field of provided position2d interface
+    will be filled according to sensor readings.
+- stall_threshold (float)
+  - Default: 0.025
+  - Distance below this value causes robot to be stalled.
+
+Since initialization routine takes some time to do its job, it may be
+worth to set alwayson to 1, as some libplayerc client programs may
+refuse to work due to communication timeout at the startup.
+
+...@par Example
+
+...@verbatim
+driver
+(
+  name "hemisson"
+  provides ["position2d:0" "ranger:0"]
+  port "/dev/ttyS1"
+  alwayson 1
+)
+...@endverbatim
+
+...@author Paul Osmialowski based on Khepera driver by Toby Collett
+*/
+/** @} */
+
+#include "hemisson_serial.h"
+
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <assert.h>
+#include <pthread.h>
+
+#include <libplayercore/playercore.h>
+
+#define EPS 0.00000000001
+
+#define HEMISSON_RANGES 8
+#define HEMISSON_WIDTH 0.11
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846
+#endif
+
+// Convert degrees to radians
+#ifndef DTOR
+#define DTOR(d) ((d) * (M_PI) / 180.0)
+#endif
+
+#ifndef RTOD
+#define RTOD(r) ((r) * 180.0 / M_PI)
+#endif
+
+class Hemisson : public ThreadedDriver
+{
+public:
+  Hemisson(ConfigFile * cf, int section);
+  virtual ~Hemisson();
+
+  virtual void Main();
+
+  virtual int MainSetup();
+  virtual void MainQuit();
+  virtual int ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr, 
void * data);
+private:
+  HemissonSerial * serial;
+  int debug;
+  player_devaddr_t position2d_addr;
+  player_devaddr_t ranger_addr;
+  const char * port;
+  int sleep_nsec;
+  int init_motor_state;
+  int motor_state;
+  double speed_factor;
+  double aspeed_factor;
+  int publish_ranges;
+  int set_stall;
+  double stall_threshold;
+  int stalled;
+  int prev_speed[2];
+  double prev_vel;
+  static double btm(int i);
+};
+
+Hemisson::Hemisson(ConfigFile * cf, int section)
+  : ThreadedDriver(cf, section, true, PLAYER_MSGQUEUE_DEFAULT_MAXLEN)
+{
+  this->serial = NULL;
+  this->debug = 0;
+  memset(&(this->position2d_addr), 0, sizeof(player_devaddr_t));
+  memset(&(this->ranger_addr), 0, sizeof(player_devaddr_t));
+  this->port = NULL;
+  this->sleep_nsec = 0;
+  this->init_motor_state = 0;
+  this->motor_state = 0;
+  this->speed_factor = 0.0;
+  this->publish_ranges = 0;
+  this->set_stall = 0;
+  this->stall_threshold = 0.0;
+  this->stalled = 0;
+  this->prev_speed[0] = 0;
+  this->prev_speed[1] = 0;
+  this->prev_vel = 0.0;
+  if (cf->ReadDeviceAddr(&(this->position2d_addr), section, "provides", 
PLAYER_POSITION2D_CODE, -1, NULL))
+  {
+    this->SetError(-1);
+    return;
+  }
+  if (this->AddInterface(this->position2d_addr))
+  {
+    this->SetError(-1);
+    return;
+  }
+  if (cf->ReadDeviceAddr(&(this->ranger_addr), section, "provides", 
PLAYER_RANGER_CODE, -1, NULL))
+  {
+    this->SetError(-1);
+    return;
+  }
+  if (this->AddInterface(this->ranger_addr))
+  {
+    this->SetError(-1);
+    return;
+  }
+  this->port = cf->ReadString(section, "port", HEMISSON_DEFAULT_SERIAL_PORT);
+  if (!(this->port))
+  {
+    this->SetError(-1);
+    return;
+  }
+  if (!(strlen(this->port) > 0))
+  {
+    this->SetError(-1);
+    return;
+  }
+  this->debug = cf->ReadInt(section, "debug", 0);
+  this->sleep_nsec = cf->ReadInt(section, "sleep_nsec", 100000000);
+  if ((this->sleep_nsec) < 0)
+  {
+    this->SetError(-1);
+    return;
+  }
+  this->init_motor_state = cf->ReadInt(section, "init_motor_state", 0);
+  this->speed_factor = cf->ReadFloat(section, "speed_factor", 18.0);
+  this->aspeed_factor = cf->ReadFloat(section, "aspeed_factor", 16.0);
+  this->publish_ranges = cf->ReadInt(section, "publish_ranges", 8);
+  if (((this->publish_ranges) < 1) || ((this->publish_ranges) > 
HEMISSON_RANGES))
+  {
+    PLAYER_ERROR("Invalid number of ranges to publish");
+    this->SetError(-1);
+    return;
+  }
+  this->set_stall = cf->ReadInt(section, "set_stall", 0);
+  if ((this->set_stall) && (this->publish_ranges < 6))
+  {
+    PLAYER_ERROR("Stall detection needs at least 6 ir ranger sensors");
+    this->SetError(-1);
+    return;
+  }
+  this->stall_threshold = cf->ReadFloat(section, "stall_threshold", 0.025);
+  if ((this->stall_threshold) < 0.0)
+  {
+    this->SetError(-1);
+    return;
+  }
+}
+
+Hemisson::~Hemisson()
+{
+  if (this->serial) delete this->serial;
+  this->serial = NULL;
+}
+
+int Hemisson::MainSetup()
+{
+  try
+  {
+    this->serial = new HemissonSerial(this->debug, this->port);
+  } catch (...)
+  {
+    this->serial = NULL;
+  }
+  if (!(this->serial)) return -1;
+  return 0;
+}
+
+void Hemisson::MainQuit()
+{
+  if (this->serial) delete this->serial;
+  this->serial = NULL;
+}
+
+void Hemisson::Main()
+{
+  struct timespec tspec;
+  double rrval[HEMISSON_RANGES];
+  player_ranger_data_range_t ranges = { 
static_cast<uint32_t>(this->publish_ranges), rrval };
+  int rval[HEMISSON_RANGES];
+  player_position2d_data_t pose;
+  int i;
+
+  this->motor_state = this->init_motor_state;
+  this->prev_speed[0] = -1000;
+  this->prev_speed[1] = -1000;
+  this->prev_vel = 0.0;
+  this->stalled = 0;
+  for (;;)
+  {
+    pthread_testcancel();
+    this->ProcessMessages();
+    pthread_testcancel();
+    if (!(this->serial->HemissonCommand('N', 0, NULL, HEMISSON_RANGES, rval)))
+    {
+      assert((ranges.ranges_count) == 
static_cast<uint32_t>(this->publish_ranges));
+      assert(ranges.ranges);
+      for (i = 0; i < (this->publish_ranges); i++)
+      {
+        ranges.ranges[i] = Hemisson::btm(rval[i]);
+      }
+      if (this->set_stall)
+      {
+        if ((this->prev_vel) > EPS)
+        {
+          if (((ranges.ranges[0]) < (this->stall_threshold)) || 
((ranges.ranges[1]) < (this->stall_threshold)) || ((ranges.ranges[2]) < 
(this->stall_threshold))) this->stalled = !0;
+          else this->stalled = 0;
+        } else if ((this->prev_vel) < (-EPS))
+        {
+          if ((ranges.ranges[5]) < (this->stall_threshold)) this->stalled = !0;
+          else this->stalled = 0;
+        }
+      }
+      this->Publish(this->ranger_addr, PLAYER_MSGTYPE_DATA, 
PLAYER_RANGER_DATA_RANGE, reinterpret_cast<void *>(&ranges));
+    }
+    pthread_testcancel();
+    memset(&(pose), 0, sizeof pose);
+    pose.stall = (this->set_stall) ? (this->stalled) : 0;
+    this->Publish(this->position2d_addr, PLAYER_MSGTYPE_DATA, 
PLAYER_POSITION2D_DATA_STATE, reinterpret_cast<void *>(&pose));
+    pthread_testcancel();
+    if (this->sleep_nsec > 0)
+    {
+      tspec.tv_sec = 0;
+      tspec.tv_nsec = this->sleep_nsec;
+      nanosleep(&tspec, NULL);
+    }
+  }
+}
+
+int Hemisson::ProcessMessage(QueuePointer & resp_queue, player_msghdr * hdr, 
void * data)
+{
+  player_ranger_geom_t ranger_geom;
+  player_pose3d_t ranger_poses[HEMISSON_RANGES];
+  player_bbox3d_t ranger_sizes[HEMISSON_RANGES];
+  player_ranger_config_t ranger_config;
+  player_position2d_geom_t position_geom;
+  player_position2d_power_config_t * position_power;
+  player_position2d_cmd_vel_t * position_cmd;
+  int i, rotvel, speed[2];
+  double d;
+
+  assert(hdr);
+  if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, 
PLAYER_RANGER_REQ_GET_GEOM, this->ranger_addr))
+  {
+    memset(&ranger_geom, 0, sizeof ranger_geom);
+    ranger_geom.size.sw = HEMISSON_WIDTH;
+    ranger_geom.size.sl = 0.13;
+    ranger_geom.size.sh = 0.006;
+    ranger_geom.element_poses_count = 
static_cast<uint32_t>(this->publish_ranges);
+    ranger_geom.element_poses = ranger_poses;
+    assert(ranger_geom.element_poses);
+    memset(&(ranger_geom.element_poses[0]), 0, sizeof 
ranger_geom.element_poses[0]);
+    ranger_geom.element_poses[0].px = 0.06;
+    ranger_geom.element_poses[0].py = 0.0;
+    ranger_geom.element_poses[0].pz = 0.0;
+    ranger_geom.element_poses[0].pyaw = DTOR(0.0);
+    memset(&(ranger_geom.element_poses[1]), 0, sizeof 
ranger_geom.element_poses[1]);
+    ranger_geom.element_poses[1].px = 0.055;
+    ranger_geom.element_poses[1].py = -0.04;
+    ranger_geom.element_poses[1].pz = 0.0;
+    ranger_geom.element_poses[1].pyaw = DTOR(-45.0);
+    memset(&(ranger_geom.element_poses[2]), 0, sizeof 
ranger_geom.element_poses[2]);
+    ranger_geom.element_poses[2].px = 0.055;
+    ranger_geom.element_poses[2].py = 0.04;
+    ranger_geom.element_poses[2].pz = 0.0;
+    ranger_geom.element_poses[2].pyaw = DTOR(45.0);
+    memset(&(ranger_geom.element_poses[3]), 0, sizeof 
ranger_geom.element_poses[3]);
+    ranger_geom.element_poses[3].px = 0.0;
+    ranger_geom.element_poses[3].py = -0.04;
+    ranger_geom.element_poses[3].pz = 0.0;
+    ranger_geom.element_poses[3].pyaw = DTOR(-90.0);
+    memset(&(ranger_geom.element_poses[4]), 0, sizeof 
ranger_geom.element_poses[4]);
+    ranger_geom.element_poses[4].px = 0.0;
+    ranger_geom.element_poses[4].py = 0.04;
+    ranger_geom.element_poses[4].pz = 0.0;
+    ranger_geom.element_poses[4].pyaw = DTOR(90.0);
+    memset(&(ranger_geom.element_poses[5]), 0, sizeof 
ranger_geom.element_poses[5]);
+    ranger_geom.element_poses[5].px = -0.06;
+    ranger_geom.element_poses[5].py = 0.0;
+    ranger_geom.element_poses[5].pz = 0.0;
+    ranger_geom.element_poses[5].pyaw = DTOR(180.0);
+    memset(&(ranger_geom.element_poses[6]), 0, sizeof 
ranger_geom.element_poses[6]);
+    ranger_geom.element_poses[6].ppitch = DTOR(90.0);
+    memset(&(ranger_geom.element_poses[7]), 0, sizeof 
ranger_geom.element_poses[7]);
+    ranger_geom.element_poses[7].ppitch = DTOR(-90.0);
+    ranger_geom.element_sizes_count = 
static_cast<uint32_t>(this->publish_ranges);
+    ranger_geom.element_sizes = ranger_sizes;
+    assert(ranger_geom.element_sizes);
+    for (i = 0; i < HEMISSON_RANGES; i++)
+    {
+      memset(&(ranger_geom.element_sizes[i]), 0, sizeof 
ranger_geom.element_sizes[i]);
+      ranger_geom.element_sizes[i].sw = 0.003;
+      ranger_geom.element_sizes[i].sl = 0.007;
+      ranger_geom.element_sizes[i].sh = 0.006;
+    }
+    this->Publish(this->ranger_addr, resp_queue,  PLAYER_MSGTYPE_RESP_ACK, 
PLAYER_RANGER_REQ_GET_GEOM, reinterpret_cast<void *>(&ranger_geom));
+    return 0;
+  }
+  if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, 
PLAYER_RANGER_REQ_GET_CONFIG, this->ranger_addr))
+  {
+    // as in sonartoranger.cc: no config for this device, so send back a pile 
of zeroes
+    memset(&ranger_config, 0, sizeof ranger_config);
+    this->Publish(this->ranger_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, 
PLAYER_RANGER_REQ_GET_CONFIG, reinterpret_cast<void *>(&ranger_config));
+    return 0;
+  }
+  if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, 
PLAYER_POSITION2D_REQ_GET_GEOM, this->position2d_addr))
+  {
+    memset(&position_geom, 0, sizeof position_geom);
+    position_geom.size.sw = HEMISSON_WIDTH;
+    position_geom.size.sl = 0.13;
+    position_geom.size.sh = 0.05;
+    this->Publish(this->position2d_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, 
PLAYER_POSITION2D_REQ_GET_GEOM, reinterpret_cast<void *>(&position_geom));
+    return 0;
+  }
+  if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_REQ, 
PLAYER_POSITION2D_REQ_MOTOR_POWER, this->position2d_addr))
+  {
+    assert(data);
+    position_power = reinterpret_cast<player_position2d_power_config_t 
*>(data);
+    assert(position_power);
+    this->motor_state = position_power->state;
+    this->Publish(this->position2d_addr, resp_queue, PLAYER_MSGTYPE_RESP_ACK, 
PLAYER_POSITION2D_REQ_MOTOR_POWER);
+    return 0;
+  }
+  if (Message::MatchMessage(hdr, PLAYER_MSGTYPE_CMD, 
PLAYER_POSITION2D_CMD_VEL, this->position2d_addr))
+  {
+    assert(data);
+    position_cmd = reinterpret_cast<player_position2d_cmd_vel_t *>(data);
+    assert(position_cmd);
+    d = (position_cmd->vel.px) * (this->speed_factor);
+    i = static_cast<int>(d);
+    if (d > EPS)
+    {
+      if (static_cast<double>(i) < d) i++;
+    } else if (d < (-EPS))
+    {
+      if (static_cast<double>(i) > d) i--;
+    } else i = 0;
+    speed[0] = i;
+    speed[1] = i;
+    if (fabs(position_cmd->vel.pa) > EPS)
+    {
+      rotvel = static_cast<int>(RTOD(position_cmd->vel.pa) * 
(this->aspeed_factor) * M_PI * (HEMISSON_WIDTH * 10.0) / 360.0);
+      speed[0] -= rotvel;
+      speed[1] += rotvel;
+    }
+    if (this->debug) PLAYER_WARN4("vel: %.4f, %.4f - speed: %d, %d", 
position_cmd->vel.px, position_cmd->vel.pa, speed[0], speed[1]);
+    if (speed[0] > 9) speed[0] = 9;
+    if (speed[0] < -9) speed[0] = -9;
+    if (speed[1] > 9) speed[1] = 9;
+    if (speed[1] < -9) speed[1] = -9;
+    if (this->motor_state)
+    {
+      if (((this->prev_speed[0]) != speed[0]) || ((this->prev_speed[1]) != 
speed[1]))
+      {
+        this->prev_speed[0] = speed[0];
+        this->prev_speed[1] = speed[1];
+        this->serial->HemissonCommand('D', 2, speed, 0, NULL);
+      }
+      this->prev_vel = position_cmd->vel.px;
+    }
+    return 0;
+  }
+  return -1;
+}
+
+double Hemisson::btm(int i)
+{
+  if (i > 250) return EPS;
+  if (i > 100) return 0.01;
+  if (i > 50) return 0.02 - (static_cast<double>(i) / 100000.0);
+  if (i > 20) return 0.03 - (static_cast<double>(i) / 10000.0);
+  return 0.08 - (static_cast<double>(i) / 1000.0);
+}
+
+Driver * Hemisson_Init(ConfigFile * cf, int section)
+{
+  return reinterpret_cast<Driver *>(new Hemisson(cf, section));
+}
+
+void hemisson_Register(DriverTable * table)
+{
+  table->AddDriver("hemisson", Hemisson_Init);
+}
+

Added: code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.cc
===================================================================
--- code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.cc          
                (rev 0)
+++ code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.cc  
2010-07-08 03:21:37 UTC (rev 8819)
@@ -0,0 +1,570 @@
+/*
+ *  Serial communication helper class for Hemisson robot driver
+ *  Copyright (C) 2010 Paul Osmialowski
+ *  Based on Minicom code released on the same license
+ *  Minicom is Copyright (C) 1991,1992,1993,1994,1995,1996
+ *      Miquel van Smoorenburg.
+ *
+ *  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
+ *
+ */
+
+#include "hemisson_serial.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <time.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define FAIL -1
+
+#ifndef CRTSCTS
+#ifdef IHFLOW
+#ifdef OHFLOW
+#define CRTSCTS ((IHFLOW) | (OHFLOW))
+#endif
+#endif
+#endif
+
+HemissonSerial::HemissonSerial(int debug, const char * port, const char * 
rate) : debug(debug)
+{
+       int beep[1];
+       fd = -1;
+       parity = 0;
+       ttybuf[0] = 0;
+        struct timespec ts;
+
+       // open the serial port
+       fd = serial_open(port);
+       if (fd < 0)
+       {
+               fprintf(stderr, "Could not open serial device %s\n", port);
+               return;
+       }
+       m_setparms(fd, rate, "N", "8", "1", 0, 0);
+       tcflush(fd, TCIOFLUSH);
+       // communication sanity check
+       printf("Hemisson> %s\n", m_gets(fd, HEMISSON_SERIAL_TIMEOUT_USECS));
+       printf("Hemisson> %s\n", m_gets(fd, HEMISSON_SERIAL_TIMEOUT_USECS));
+       // clear the input buffer in case junk data is on the port
+       HemissonCommand('B', 0, NULL, 0, NULL);
+       tcflush(fd, TCIFLUSH);
+       // try a test command
+       beep[0] = 1;
+       HemissonCommand('H', 1, beep, 0, NULL);
+        ts.tv_sec = 0;
+        ts.tv_nsec = 500000000;
+        nanosleep(&ts, NULL);
+       beep[0] = 0;
+       HemissonCommand('H', 1, beep, 0, NULL);
+}
+
+HemissonSerial::~HemissonSerial()
+{
+       if (fd > 0)
+       {
+               serial_close(fd);
+       }
+}
+
+int HemissonSerial::WriteInts(char command, int Count, int * Values)
+{
+       int i;
+
+       if (fd < 0) return -1;
+       buffer[0] = command;
+       buffer[1] = '\0';
+       int length;
+       if (Values) for (i = 0; i < Count; ++ i)
+       {
+               length = strlen(buffer);
+               snprintf(&buffer[length],HEMISSON_BUFFER_LEN - length - 
2,",%d",Values[i]);
+       }
+       if (debug)
+       {
+           printf(">>>> %s\n", buffer); fflush(stdout);
+       }
+       m_puts(fd, buffer);
+       return 0;
+}
+
+#define MAX_RETRIES 5
+// read ints from Hemisson
+int HemissonSerial::ReadInts(char Header, int Count, int * Values)
+{
+       int i;
+
+       buffer[0] = 0;
+       if (fd < 0) return -1;
+       for (i = 0; i < MAX_RETRIES; i++)
+       {
+           strncpy(buffer, m_gets(fd, HEMISSON_SERIAL_TIMEOUT_USECS), 
HEMISSON_BUFFER_LEN);
+           if (debug)
+           {
+               printf("[%d] %s\n", i, buffer); fflush(stdout);
+           }
+           if (buffer[0]) break;
+           m_puts(fd, "B");
+       }
+       if (buffer[0] != Header) return -1;
+       char * pos = &buffer[2];
+       if (Values) for (i = 0; i < Count; i++)
+       {
+               Values[i] = strtol(pos, &pos, 10);
+               pos++;
+       }
+       return 0;
+}
+
+int HemissonSerial::HemissonCommand(char command, int InCount, int * InValues, 
int OutCount, int * OutValues)
+{
+        struct timespec ts;
+        int ret2;
+
+        WriteInts(command,InCount,InValues);
+        ts.tv_sec = 0;
+        ts.tv_nsec = 50000000;
+        nanosleep(&ts, NULL);
+        ret2 = ReadInts(command + 32, OutCount, OutValues);
+        ts.tv_sec = 0;
+        ts.tv_nsec = 50000000;
+        nanosleep(&ts, NULL);
+        return ret2;
+}
+
+char * HemissonSerial::m_gets(int fd, int tmout)
+{
+  int n, f, q;
+  struct timeval tv;
+  fd_set fds;
+  char * buf;
+
+  buf = ttybuf; f = 0; q = 0;
+
+  for (;;)
+  {
+    buf[0]=0;
+    // tv.tv_sec = tmout / 1000;
+    // tv.tv_usec = (tmout % 1000) * 1000L;
+    tv.tv_sec = 0;
+    tv.tv_usec = tmout;
+
+    FD_ZERO(&fds);
+    FD_SET(fd, &fds);
+
+    if (select(fd + 1, &fds, NULL, NULL, &tv) > 0)
+    {
+      if (FD_ISSET(fd, &fds) > 0)
+      {
+        n = read(fd, buf, 1);
+        if (n > 0)
+        {
+          if (q)
+          {
+            buf++;
+            buf[0] = 0;
+            if ((parity == 'M') || (parity == 'S')) ttybuf[0] &= 0x7f;
+            return ttybuf;
+          }
+          switch(buf[0])
+          {
+          case 10:
+            buf[0] = 0;
+            if ((parity == 'M') || (parity == 'S')) ttybuf[0] &= 0x7f;
+            return ttybuf;
+          case 13:
+            buf[0] = 0;
+            break;
+          case 16:
+            buf[0] = 0;
+            q = !0;
+            break;
+          default:
+            buf++; f++;
+            if (f >= TTYBUFFLEN)
+            {
+              buf[0] = 0;
+              if ((parity == 'M') || (parity == 'S')) ttybuf[0] &= 0x7f;
+              return ttybuf;
+            }
+          }
+        }
+      }
+    } else break;
+  }
+  if ((parity == 'M') || (parity == 'S')) ttybuf[0] &= 0x7f;
+  return ttybuf;
+}
+
+int HemissonSerial::m_getchar(int fd, int tmout)
+{
+  int n;
+  struct timeval tv;
+  fd_set fds;
+
+  // tv.tv_sec = tmout / 1000;
+  // tv.tv_usec = (tmout % 1000) * 1000L;
+  tv.tv_sec = 0;
+  tv.tv_usec = tmout;
+
+  FD_ZERO(&fds);
+  FD_SET(fd, &fds);
+
+  if (select(fd + 1, &fds, NULL, NULL, &tv) > 0)
+  {
+    if (FD_ISSET(fd, &fds) > 0)
+    {
+      n = read(fd, ttybuf, 1);
+      if (n > 0) return static_cast<int>(static_cast<unsigned 
char>(ttybuf[0]));
+    }
+  }
+  return -1;
+}
+
+/*
+ * Send a string to the modem.
+ */
+void HemissonSerial::m_puts(int fd, const char * s)
+{
+  struct timespec ts;
+  char c;
+
+  while (*s)
+  {
+       if (*s == '^' && (*(s + 1)))
+        {
+               s++;
+               if (*s == '^')
+                       c = *s;
+               else
+                       c = (*s) & 31;
+       } else c = *s;
+       if (c == '~')
+        {
+                ts.tv_sec = 1;
+                ts.tv_nsec = 0;
+                nanosleep(&ts, NULL);
+       } else write(fd, &c, 1);
+       s++;
+  }
+  c = 13;
+  write(fd, &c, 1);
+}
+
+void HemissonSerial::m_putchar(int fd, int chr)
+{
+    char c;
+    struct timespec ts;
+
+    c = static_cast<char>(chr);
+    if (c == '~')
+    {
+        ts.tv_sec = 1;
+        ts.tv_nsec = 0;
+        nanosleep(&ts, NULL);
+    } else write(fd, &c, 1);
+}
+
+/* Set hardware flow control. */
+void HemissonSerial::m_sethwf(int fd, int on)
+{
+  struct termios tty;
+
+  tcgetattr(fd, &tty);
+  if (on)
+       tty.c_cflag |= CRTSCTS;
+  else
+       tty.c_cflag &= ~CRTSCTS;
+  tcsetattr(fd, TCSANOW, &tty);
+}
+
+/* Set RTS line. Sometimes dropped. Linux specific? */
+void HemissonSerial::m_setrts(int fd)
+{
+#if defined(TIOCM_RTS) && defined(TIOCMGET)
+  int mcs=0;
+
+  ioctl(fd, TIOCMGET, &mcs);
+  mcs |= TIOCM_RTS;
+  ioctl(fd, TIOCMSET, &mcs);
+#endif
+}
+
+/*
+ * Drop DTR line and raise it again.
+ */
+void HemissonSerial::m_dtrtoggle(int fd, int sec)
+{
+  /* Posix - set baudrate to 0 and back */
+  struct termios tty, old;
+  struct timespec ts;
+
+  tcgetattr(fd, &tty);
+  tcgetattr(fd, &old);
+  cfsetospeed(&tty, B0);
+  cfsetispeed(&tty, B0);
+  tcsetattr(fd, TCSANOW, &tty);
+  if (sec > 0)
+  {
+    ts.tv_sec = sec;
+    ts.tv_nsec = 0;
+    nanosleep(&ts, NULL);
+    tcsetattr(fd, TCSANOW, &old);
+  }
+}
+
+/*
+ * Send a break
+ */
+void HemissonSerial::m_break(int fd)
+{
+  tcsendbreak(fd, 0);
+}
+
+/*
+ * Get the dcd status
+ */
+int HemissonSerial::m_getdcd(int fd)
+{
+#ifdef TIOCMGET
+  int mcs=0;
+
+  ioctl(fd, TIOCMGET, &mcs);
+  return (mcs & TIOCM_CAR) ? 1 : 0;
+#else
+  fd = fd;
+  return 0; /* Impossible!! (eg. Coherent) */
+#endif
+}
+
+/*
+ * Save the state of a port
+ */
+void HemissonSerial::m_savestate(int fd)
+{
+  tcgetattr(fd, &savetty);
+#ifdef TIOCMGET
+  ioctl(fd, TIOCMGET, &m_word);
+#endif
+}
+
+/*
+ * Restore the state of a port
+ */
+void HemissonSerial::m_restorestate(int fd)
+{
+  tcsetattr(fd, TCSANOW, &savetty);
+#ifdef TIOCMSET
+  ioctl(fd, TIOCMSET, &m_word);
+#endif
+}
+
+/*
+ * Set the line status so that it will not kill our process
+ * if the line hangs up.
+ */
+/*ARGSUSED*/ 
+void HemissonSerial::m_nohang(int fd)
+{
+  struct termios sgg;
+
+  tcgetattr(fd, &sgg);
+  sgg.c_cflag |= CLOCAL;
+  tcsetattr(fd, TCSANOW, &sgg);
+}
+
+/*
+ * Set hangup on close on/off.
+ */
+void HemissonSerial::m_hupcl(int fd, int on)
+{
+  struct termios sgg;
+
+  tcgetattr(fd, &sgg);
+  if (on) sgg.c_cflag |= HUPCL;
+  else sgg.c_cflag &= ~HUPCL;
+  tcsetattr(fd, TCSANOW, &sgg);
+}
+
+/*
+ * Flush the buffers
+ */
+void HemissonSerial::m_flush(int fd)
+{
+/* Should I Posixify this, or not? */
+#ifdef TCFLSH
+  ioctl(fd, TCFLSH, 2);
+#endif
+#ifdef TIOCFLUSH
+  ioctl(fd, TIOCFLUSH, NULL);
+#endif
+}
+
+/*
+ * Set baudrate, parity and number of bits.
+ */
+void HemissonSerial::m_setparms(int fd, const char * baudr, const char * par, 
const char * bits, const char * stopb, int hwf, int swf)
+{
+  int spd = -1;
+  int newbaud;
+  int bit = bits[0];
+
+  struct termios tty;
+
+  tcgetattr(fd, &tty);
+
+  /* We generate mark and space parity ourself. */
+  parity = par[0];
+  if (bit == '7' && (par[0] == 'M' || par[0] == 'S'))
+       bit = '8';
+
+  /* Check if 'baudr' is really a number */
+  if ((newbaud = (atol(baudr) / 100)) == 0 && baudr[0] != '0') newbaud = -1;
+
+  switch(newbaud) {
+       case 0:         spd = B0;       break;
+       case 3:         spd = B300;     break;
+       case 6:         spd = B600;     break;
+       case 12:        spd = B1200;    break;
+       case 24:        spd = B2400;    break;
+       case 48:        spd = B4800;    break;
+       case 96:        spd = B9600;    break;
+#ifdef B19200
+       case 192:       spd = B19200;   break;
+#else /* B19200 */
+#ifdef EXTA
+       case 192:       spd = EXTA;     break;
+#else /* EXTA */
+       case 192:       spd = B9600;    break;
+#endif /* EXTA */
+#endif /* B19200 */
+#ifdef B38400
+       case 384:       spd = B38400;   break;
+#else /* B38400 */
+#ifdef EXTB
+       case 384:       spd = EXTB;     break;
+#else /* EXTB */
+       case 384:       spd = B9600;    break;
+#endif /* EXTB */
+#endif /* B38400 */
+#ifdef B57600
+       case 576:       spd = B57600;   break;
+#endif
+#ifdef B115200
+       case 1152:      spd = B115200;  break;
+#endif
+#ifdef B230400
+       case 2304:      spd = B230400;  break;
+#endif
+  }
+  if (spd != -1) {
+       cfsetospeed(&tty, (speed_t)spd);
+       cfsetispeed(&tty, (speed_t)spd);
+  }
+  switch (bit) {
+       case '5':
+               tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS5;
+               break;
+       case '6':
+               tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS6;
+               break;
+       case '7':
+               tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS7;
+               break;
+       case '8':
+       default:
+               tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
+               break;
+  }            
+  /* Set into raw, no echo mode */
+  tty.c_iflag =  IGNBRK;
+  tty.c_lflag = 0;
+  tty.c_oflag = 0;
+  tty.c_cflag |= CLOCAL | CREAD;
+#ifdef _DCDFLOW
+  tty.c_cflag &= ~CRTSCTS;
+#endif
+  tty.c_cc[VMIN] = 1;
+  tty.c_cc[VTIME] = 5;
+
+  if (swf)
+       tty.c_iflag |= IXON | IXOFF;
+  else
+       tty.c_iflag &= ~(IXON|IXOFF|IXANY);
+
+  tty.c_cflag &= ~(PARENB | PARODD);
+  if (par[0] == 'E')
+       tty.c_cflag |= PARENB;
+  else if (par[0] == 'O')
+       tty.c_cflag |= (PARENB | PARODD);
+
+  if (stopb[0] == '2')
+    tty.c_cflag |= CSTOPB;
+  else
+    tty.c_cflag &= ~CSTOPB;
+
+  tcsetattr(fd, TCSANOW, &tty);
+
+  m_setrts(fd);
+
+#ifndef _DCDFLOW
+  m_sethwf(fd, hwf);
+#endif
+}
+
+int HemissonSerial::serial_open(const char * devname)
+{
+    int f, portfd;
+    struct stat stt;
+
+    ttybuf[0] = 0;
+    ttybuf[TTYBUFFLEN] = 0;
+    if (stat(devname, &stt)==-1)
+    {
+        fprintf(stderr, "Cannot stat device: %s\n", devname);
+        return FAIL;
+    }
+    portfd=open(devname, O_RDWR|O_NDELAY);
+    if (portfd<0)
+    {
+        fprintf(stderr, "Cannot open device: %s\n", devname);
+        return FAIL;
+    }
+    f = fcntl (portfd, F_GETFL, 0);
+    fcntl(portfd, F_SETFL, f & ~O_NDELAY);
+    m_savestate(portfd);
+    m_nohang(portfd);
+    m_hupcl(portfd, 1);
+    m_flush(portfd);
+    return portfd;
+}
+
+void HemissonSerial::serial_close(int fd)
+{
+    if (fd >= 0)
+    {
+        m_restorestate(fd);
+        close(fd);
+    }
+}

Added: code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.h
===================================================================
--- code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.h           
                (rev 0)
+++ code/player/trunk/server/drivers/mixed/hemisson/hemisson_serial.h   
2010-07-08 03:21:37 UTC (rev 8819)
@@ -0,0 +1,85 @@
+/*
+ *  Serial communication helper class for Hemisson robot driver
+ *  Copyright (C) 2010 Paul Osmialowski
+ *  Based on Minicom code released on the same license
+ *  Minicom is Copyright (C) 1991,1992,1993,1994,1995,1996
+ *      Miquel van Smoorenburg.
+ *
+ *  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
+ *
+ */
+
+#ifndef HEMISSON_SERIAL_H
+#define HEMISSON_SERIAL_H
+
+#include <stddef.h>
+#include <termios.h>
+
+#define HEMISSON_BAUDRATE "115200"
+#define HEMISSON_DEFAULT_SERIAL_PORT "/dev/rfcomm0"
+#define HEMISSON_BUFFER_LEN 255
+#define HEMISSON_SERIAL_TIMEOUT_USECS 100000
+
+#define TTYBUFFLEN 255
+#define TTYBUFFSIZE (TTYBUFFLEN + 1)
+
+class HemissonSerial
+{
+public:
+       HemissonSerial(int debug = 0, const char * port = 
HEMISSON_DEFAULT_SERIAL_PORT, const char * rate = HEMISSON_BAUDRATE);
+       virtual ~HemissonSerial();
+
+       bool Open() { return fd >0; };
+       int HemissonCommand(char command, int InCount, int * InValues, int 
OutCount, int * OutValues);
+
+protected:
+       // serial port descriptor
+       int fd;
+       // read/write buffer
+       char buffer[HEMISSON_BUFFER_LEN + 1];
+
+       int WriteInts(char command, int Count = 0, int * Values = NULL);
+       int ReadInts(char Header, int Count = 0, int * Values = NULL);
+
+       int debug;
+
+private:
+       char ttybuf[TTYBUFFSIZE];
+       char parity;
+       struct termios savetty;
+       int m_word;
+
+       char * m_gets(int fd, int tmout);
+       int m_getchar(int fd, int tmout);
+       void m_puts(int fd, const char * s);
+       void m_putchar(int fd, int chr);
+       void m_dtrtoggle(int fd, int sec);
+       void m_break(int fd);
+       int m_getdcd(int fd);
+       void m_flush(int fd);
+       void m_setparms(int fd, const char * baudr, const char * par, const 
char * bits, const char * stopb, int hwf, int swf);
+       int serial_open(const char * devname);
+       void serial_close(int fd);
+
+       void m_sethwf(int fd, int on);
+       void m_setrts(int fd);
+       void m_savestate(int fd);
+       void m_restorestate(int fd);
+       void m_nohang(int fd);
+       void m_hupcl(int fd, int on);
+};
+
+#endif
+


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit

Reply via email to