Revision: 8020
http://playerstage.svn.sourceforge.net/playerstage/?rev=8020&view=rev
Author: gbiggs
Date: 2009-07-14 23:04:25 +0000 (Tue, 14 Jul 2009)
Log Message:
-----------
Applied patch #2821370
Modified Paths:
--------------
code/player/trunk/server/drivers/gps/CMakeLists.txt
Added Paths:
-----------
code/player/trunk/server/drivers/gps/rt3xxx.cc
Modified: code/player/trunk/server/drivers/gps/CMakeLists.txt
===================================================================
--- code/player/trunk/server/drivers/gps/CMakeLists.txt 2009-07-14 22:58:11 UTC
(rev 8019)
+++ code/player/trunk/server/drivers/gps/CMakeLists.txt 2009-07-14 23:04:25 UTC
(rev 8020)
@@ -11,3 +11,7 @@
LINKLIBS ${gbxgarminacfr_linkLibs} LINKFLAGS ${gbxgarminacfr_linkFlags}
CFLAGS ${gbxgarminacfr_cFlags} SOURCES gbxgarminacfr.cc)
+PLAYERDRIVER_OPTION (rt3xxx build_rt3xxx ON)
+PLAYERDRIVER_REJECT_OS (rt3xxx build_rt3xxx PLAYER_OS_WIN)
+PLAYERDRIVER_ADD_DRIVER (rt3xxx build_rt3xxx SOURCES rt3xxx.cc)
+
Added: code/player/trunk/server/drivers/gps/rt3xxx.cc
===================================================================
--- code/player/trunk/server/drivers/gps/rt3xxx.cc
(rev 0)
+++ code/player/trunk/server/drivers/gps/rt3xxx.cc 2009-07-14 23:04:25 UTC
(rev 8020)
@@ -0,0 +1,429 @@
+/*
+ * 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 */
+/** @{ */
+/** @defgroup driver_rt3xxx rt3xxx
+ * @brief Driver for the RT3XXX
+
+Provides a gps interface to an RT3xxx inertial navigation
+unit. It may work for other units as it only receives data
+and does not communicate with the unit.
+
+...@par Compile-time dependencies
+
+- None.
+
+...@par Provides
+
+- @ref interface_gps
+
+...@par Requires
+
+- None.
+
+...@par Configuration requests
+
+- None.
+
+...@par Configuration file options
+
+- None.
+
+...@par Example
+
+...@verbatim
+driver
+(
+ name "rt3xxx"
+ provides ["gps:0"]
+)
+...@endverbatim
+
+...@author Mike Roddewig [email protected]
+
+*/
+/** @} */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <math.h>
+
+#include <libplayercore/playercore.h>
+
+#define RT_PORT 3000 // The port the rt is broadcasting on.
+
+#define MAXBUFLEN 128
+
+// Message levels
+
+#define MESSAGE_ERROR 0
+#define MESSAGE_INFO 1
+#define MESSAGE_DEBUG 2
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// The class for the driver
+class rt3xxx : public ThreadedDriver
+{
+ public:
+ rt3xxx(ConfigFile* cf, int section);
+
+ // This method will be invoked on each incoming message
+ virtual int ProcessMessage(QueuePointer &resp_queue,
+ player_msghdr * hdr,
+ void * data);
+ virtual int MainSetup();
+ virtual void MainQuit();
+
+ private:
+ int sockfd;
+ char buf[MAXBUFLEN];
+ player_gps_data_t gps_data;
+ player_devaddr_t gps_addr;
+ double lat_long_scale_factor;
+ double rt_heading_scale_factor;
+
+ // Main function for device thread.
+ virtual void Main();
+
+ int ProcessPacket();
+
+ void PublishGPSData();
+};
+
+// 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*
+rt3xxx_Init(ConfigFile* cf, int section)
+{
+ // Create and return a new instance of this driver
+ return((Driver*)(new rt3xxx(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 rt3xxx_Register(DriverTable* table)
+{
+ table->AddDriver("rt3xxx", rt3xxx_Init);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Constructor. Retrieve options from the configuration file and do any
+// pre-Setup() setup.
+rt3xxx::rt3xxx(ConfigFile* cf, int section) : ThreadedDriver(cf, section) {
+ memset (&this->gps_addr, 0, sizeof (player_devaddr_t));
+
+ // Check the config file to see if we are providing a GPS interface.
+ if (cf->ReadDeviceAddr(&(this->gps_addr), section, "provides",
+ PLAYER_GPS_CODE, -1, NULL) == 0) {
+ if (this->AddInterface(this->gps_addr) != 0) {
+ PLAYER_ERROR("Error adding GPS interface.");
+ SetError(-1);
+ return;
+ }
+ }
+
+ return;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Set up the device. Return 0 if things go well, and -1 otherwise.
+int rt3xxx::MainSetup()
+{
+ struct sockaddr_in address;
+ int broadcast = 1;
+
+ PLAYER_MSG0(MESSAGE_INFO, "rt3xxx setting up.");
+
+ sockfd = socket(PF_INET, SOCK_DGRAM, 0);
+
+ if (sockfd == -1) {
+ PLAYER_ERROR("rt3xxx: failed to get socket.");
+ return -1;
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(RT_PORT);
+
+ if (bind(sockfd, (struct sockaddr *) &address, sizeof(address)) == -1) {
+ PLAYER_ERROR("rt3xxx: failed to bind socket.");
+ return -1;
+ }
+
+ if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof(int)) == -1) {
+ PLAYER_ERROR("rt3xxx: failed to set broadcast flag.");
+ return -1;
+ }
+
+ this->lat_long_scale_factor = pow(10.0, 7.0);
+ this->rt_heading_scale_factor = pow(10.0, -6.0);
+
+ PLAYER_MSG0(MESSAGE_INFO, "rt3xxx driver ready.");
+
+ return(0);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Shutdown the device
+void rt3xxx::MainQuit()
+{
+ PLAYER_MSG0(MESSAGE_INFO, "Shutting rt3xxx driver down.");
+
+ close(this->sockfd);
+
+ PLAYER_MSG0(MESSAGE_INFO, "rt3xxx driver has been shutdown.");
+
+ return;
+}
+
+int rt3xxx::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.
+ return(-1);
+}
+
+int rt3xxx::ProcessPacket() {
+ int numbytes;
+
+ char nav_status;
+ double latitude;
+ double * latitude_pointer;
+ double longitude;
+ double * longitude_pointer;
+ float altitude;
+ float * altitude_pointer;
+ unsigned char num_satellites;
+ unsigned char position_mode;
+ unsigned char velocity_mode;
+ static long gps_time_minutes; // The GPS time in minutes is not
transmitted
+ // with every
packet so it needs to persist over
+ // multiple
function calls.
+ double heading;
+ unsigned char hdop;
+ unsigned char pdop;
+
+
+ numbytes = recv(sockfd, &buf, MAXBUFLEN-1 , 0);
+
+ if (numbytes == -1) {
+ return -1;
+ }
+ else if (numbytes != 72) {
+ // We got a packet, but it's something weird. We'll discard it
+ // rather than take our chances.
+
+ PLAYER_MSG0(MESSAGE_DEBUG, "Received packet of the wrong
size.");
+
+ return -2;
+ }
+ else {
+ // So far, so good. Process the packet. There are certainly lots
+ // of interesting tidbits that the RT reports, but so far we
only
+ // use the data supported by the GPS interface.
+
+ if (((unsigned char) buf[numbytes-1]) != 0xE7) {
+ // We expect the last (?) character to be the "sync"
character
+ // of 0xE7. The documentation specifies that the sync
character
+ // should be the first byte of the packet but in
reality it appears
+ // to be the last. Huh.
+
+ PLAYER_MSG0(MESSAGE_DEBUG, "Failed to locate the sync
character.");
+
+ return -3;
+ }
+
+ nav_status = buf[20];
+
+ switch (nav_status) {
+ case 0x00:
+ // All quantities in the packet are invalid?!
Time to quit.
+
+ PLAYER_MSG0(MESSAGE_DEBUG, "Init state: 0. All
quantities invalid.");
+
+ return 0;
+ case 0x01:
+ // IMU measurements only. No position data.
Time to quit.
+
+ PLAYER_MSG0(MESSAGE_DEBUG, "Init state: 1. IMU
measurements only.");
+
+ return 0;
+ case 0x02:
+ // Initialization mode. No position data
(though the time
+ // is valid). Time to quit, heh.
+
+ PLAYER_MSG0(MESSAGE_DEBUG, "Init state: 2.
Initialization mode.");
+
+ return 0;
+ case 0x03:
+ // The RT is acquiring lock. Apparently this
mode lasts a
+ // max of 10 seconds, so we can wait (can
you?). Time to
+ // quit.
+
+ PLAYER_MSG0(MESSAGE_DEBUG, "Init state: 3.
Acquiring lock.");
+
+ return 0;
+ case 0x04:
+ // Locked and loaded. Let's get our data!
+
+ this->gps_data.time_sec = (uint32_t)
gps_time_minutes * 60;
+ this->gps_data.time_usec = buf[0];
+ this->gps_data.time_usec += buf[1] << 8;
+
+ // Retrieve the lat/long data. It's a real pity
that the RT
+ // does not provide position in UTM
coordinates, as every
+ // true navigation geek knows that UTM is the
superior
+ // coordinate system ;).
+
+ // I don't like it, but it appears we have to
be tricky in
+ // order to load this double into memory. We
declare a
+ // pointer and set it to start at the location
of the double
+ // in the buffer.
+
+ latitude_pointer = (double *) &buf[22];
+ latitude = *latitude_pointer;
+
+ longitude_pointer = (double *) &buf[30];
+ longitude = *longitude_pointer;
+
+ altitude_pointer = (float *) &buf[38];
+ altitude = *altitude_pointer;
+
+ heading = (double) buf[51];
+ heading += (double) (buf[52] << 8);
+ heading += (double) (buf[53] << 16);
+
+ // Convert the RT units to Player units.
+
+ // Lat/long to degrees (the RT reports in
radians).
+
+ latitude = latitude * (180.0/M_PI);
+ longitude = longitude * (180.0/M_PI);
+
+ // Apply a scaling of 10^7 (why not a power of
two Player?).
+ latitude = latitude *
this->lat_long_scale_factor;
+ longitude = longitude *
this->lat_long_scale_factor;
+
+ this->gps_data.latitude = (int32_t) latitude;
+ this->gps_data.longitude = (int32_t) longitude;
+
+ // Player wants altitude in millimeters.
+
+ this->gps_data.altitude = (int32_t) (altitude *
1000);
+
+ // Convert heading to radians and then to
degrees.
+
+ heading = heading *
this->rt_heading_scale_factor; // Convert to radians in units of one radian.
+ heading += M_PI;
+ heading = heading * (180.0/M_PI); // Convert to
degrees.
+
+ if (buf[61] == 0) {
+ // The status information contains data
we're interested
+ // in.
+
+ gps_time_minutes = buf[62];
+ gps_time_minutes += buf[63] << 8;
+ gps_time_minutes += buf[64] << 16;
+ gps_time_minutes += buf[65] << 24;
+
+ num_satellites = buf[66];
+ position_mode = buf[67];
+ velocity_mode = buf[68];
+
+ this->gps_data.num_sats = (uint32_t)
num_satellites;
+
+ if (position_mode < 2) {
+ // Invalid.
+
+ this->gps_data.quality = 0;
+ }
+ else if (position_mode < 7) {
+ // No SBAS.
+
+ this->gps_data.quality = 1;
+ }
+ else {
+ // Some form of augmentation
system is present.
+
+ this->gps_data.quality = 2;
+ }
+ }
+ else if (buf[61] == 48) {
+ hdop = buf[64];
+ pdop = buf[65];
+
+ this->gps_data.hdop = (uint32_t) (hdop
* 10);
+ }
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Main function for device thread
+void rt3xxx::Main()
+{
+ // The main loop; interact with the device here
+ for(;;)
+ {
+ ProcessPacket();
+
+ // Publish the received data.
+ rt3xxx::PublishGPSData();
+ }
+}
+
+void rt3xxx::PublishGPSData() {
+ this->Publish(
+ this->gps_addr,
+ PLAYER_MSGTYPE_DATA,
+ PLAYER_GPS_DATA_STATE,
+ (void *) &this->gps_data,
+ sizeof(player_gps_data_t),
+ NULL
+ );
+}
+
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Enter the BlackBerry Developer Challenge
This is your chance to win up to $100,000 in prizes! For a limited time,
vendors submitting new applications to BlackBerry App World(TM) will have
the opportunity to enter the BlackBerry Developer Challenge. See full prize
details at: http://p.sf.net/sfu/Challenge
_______________________________________________
Playerstage-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/playerstage-commit