From f53fab80fd7ef9c2a0fd7cc1291bd4e896c706c7 Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Tue, 30 Dec 2014 15:48:41 -0700 Subject: [PATCH] ublox6: Initial implementation jrvandr: removed unnecessary mraa_init() and mraa_deinit() The module implements support for the ublox-6 GPS sensor. It was tested on a Grove GPS device. This module simply allows data to be retrieved from the device in the form of NMEA sentences, and provides a method to write commands to the device for configuration purposes. It does not attempt to parse NMEA data -- that is a project in itself. There are libraries available on the Internet, such as tinyGPS++ that can handle that for you. Signed-off-by: Jon Trulson Signed-off-by: Zion Orent Signed-off-by: John Van Drasek --- examples/CMakeLists.txt | 3 + examples/javascript/ublox6.js | 99 ++++++++++++++++++++++++ examples/ublox6.cxx | 107 ++++++++++++++++++++++++++ src/ublox6/CMakeLists.txt | 5 ++ src/ublox6/jsupm_ublox6.i | 13 ++++ src/ublox6/pyupm_ublox6.i | 9 +++ src/ublox6/ublox6.cxx | 140 ++++++++++++++++++++++++++++++++++ src/ublox6/ublox6.h | 117 ++++++++++++++++++++++++++++ 8 files changed, 493 insertions(+) create mode 100644 examples/javascript/ublox6.js create mode 100644 examples/ublox6.cxx create mode 100644 src/ublox6/CMakeLists.txt create mode 100644 src/ublox6/jsupm_ublox6.i create mode 100644 src/ublox6/pyupm_ublox6.i create mode 100644 src/ublox6/ublox6.cxx create mode 100644 src/ublox6/ublox6.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 91534b9d..fc369ac8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -66,6 +66,7 @@ add_executable (grovewater-example grovewater.cxx) add_executable (guvas12d-example guvas12d.cxx) add_executable (groveloudness-example groveloudness.cxx) add_executable (mpr121-example mpr121.cxx) +add_executable (ublox6-example ublox6.cxx) include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l) include_directories (${PROJECT_SOURCE_DIR}/src/grove) @@ -119,6 +120,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/grovewater) include_directories (${PROJECT_SOURCE_DIR}/src/guvas12d) include_directories (${PROJECT_SOURCE_DIR}/src/groveloudness) include_directories (${PROJECT_SOURCE_DIR}/src/mpr121) +include_directories (${PROJECT_SOURCE_DIR}/src/ublox6) target_link_libraries (hmc5883l-example hmc5883l ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveled-example grove ${CMAKE_THREAD_LIBS_INIT}) @@ -188,3 +190,4 @@ target_link_libraries (grovewater-example grovewater ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (guvas12d-example guvas12d ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (groveloudness-example groveloudness ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries (mpr121-example mpr121 ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries (ublox6-example ublox6 ${CMAKE_THREAD_LIBS_INIT}) diff --git a/examples/javascript/ublox6.js b/examples/javascript/ublox6.js new file mode 100644 index 00000000..7a356236 --- /dev/null +++ b/examples/javascript/ublox6.js @@ -0,0 +1,99 @@ +/*jslint node:true, vars:true, bitwise:true, unparam:true */ +/*jshint unused:true */ +/*global */ +/* +* Author: Zion Orent +* Copyright (c) 2014 Intel Corporation. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +var GPSSensor = require('jsupm_ublox6'); + +// Instantiate a Ublox6 GPS device on uart 0 (/dev/ttyS0). This +// works for the galileo G2. + +// The Edison uses a different serial port, /dev/ttyMFD1, so if you +// are using this example on an Edison board, specify the proper +// port on the command line, eg: 'node ublox6.js /dev/ttyMFD1' +// process.argv.length contains all command-line strings +// argument 0 is "node" +// argument 1 is "ublox6.js" +// argument 2, if it exists, will be the override port, +// such as /dev/ttyMFD1 on Edison + +var defaultPort = "/dev/ttyS0"; +if (process.argv.length > 2) + defaultPort = process.argv[2]; + +var myGPSSensor = new GPSSensor.Ublox6(0, defaultPort); + +if (!myGPSSensor.setupTty(GPSSensor.int_B9600)) +{ + console.log("Failed to setup tty port parameters"); + process.exit(0); +} + +// Collect and output NMEA data. + +// This device also supports numerous configuration options, which +// you can set with writeData(). Please refer to the Ublox-6 data +// sheet for further information on the formats of the data sent and +// received, and the various operating modes available. + +var bufferLength = 256; +var nmeaBuffer = new GPSSensor.charArray(bufferLength); + +function getGPSInfo() +{ + // we don't want the read to block in this example, so always + // check to see if data is available first. + if (myGPSSensor.dataAvailable()) + { + var rv = myGPSSensor.readData(nmeaBuffer, bufferLength); + + var GPSData, dataCharCode, isNewLine, lastNewLine; + var numlines= 0; + if (rv > 0) + { + GPSData = ""; + // read only the number of characters + // specified by myGPSSensor.readData + for (var x = 0; x < rv; x++) + GPSData += nmeaBuffer.getitem(x); + process.stdout.write(GPSData) + } + + if (rv < 0) // some sort of read error occured + { + console.log("Port read error."); + process.exit(0); + } + } +} + +setInterval(getGPSInfo, 100); + +// Print message when exiting +process.on('SIGINT', function() +{ + console.log("Exiting..."); + process.exit(0); +}); diff --git a/examples/ublox6.cxx b/examples/ublox6.cxx new file mode 100644 index 00000000..3dcc423a --- /dev/null +++ b/examples/ublox6.cxx @@ -0,0 +1,107 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2014 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include "ublox6.h" + +using namespace std; + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +const size_t bufferLength = 256; + +int main (int argc, char **argv) +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + // Instantiate a Ublox6 GPS device on uart 0 (/dev/ttyS0). This + // works for the galileo G2. + + // The Edison uses a different serial port, /dev/ttyMFD1, so if you + // are using this example on an Edison board, specify the proper + // port on the command line, eg: './ublox6-example /dev/ttyMFD1' + + const char *defaultPort = "/dev/ttyS0"; + if (argc > 1) + defaultPort = argv[1]; + + upm::Ublox6* nmea = new upm::Ublox6(0, defaultPort); + + // make sure port is initialized properly. 9600 baud is the default. + if (!nmea->setupTty(B9600)) + { + cerr << "Failed to setup tty port parameters" << endl; + return 1; + } + + // Collect and output NMEA data. There are various libraries out on + // the Internet, such as tinyGPS or tinyGPS++ that can handle + // decoding NMEA data and presenting it in a more easily accessable + // format. This example will just check for, and read raw NMEA data + // from the device and output it on stdout. + + // This device also supports numerous configuration options, which + // you can set with writeData(). Please refer to the Ublox-6 data + // sheet for further information on the formats of the data sent and + // received, and the various operating modes available. + + char nmeaBuffer[bufferLength]; + while (shouldRun) + { + // we don't want the read to block in this example, so always + // check to see if data is available first. + if (nmea->dataAvailable()) + { + int rv = nmea->readData(nmeaBuffer, bufferLength); + + if (rv > 0) + write(1, nmeaBuffer, rv); + + if (rv < 0) // some sort of read error occured + { + cerr << "Port read error." << endl; + break; + } + + continue; + } + + usleep(100000); // 100ms + } +//! [Interesting] + + cout << "Exiting..." << endl; + + delete nmea; + return 0; +} diff --git a/src/ublox6/CMakeLists.txt b/src/ublox6/CMakeLists.txt new file mode 100644 index 00000000..5db12669 --- /dev/null +++ b/src/ublox6/CMakeLists.txt @@ -0,0 +1,5 @@ +set (libname "ublox6") +set (libdescription "upm u-blox 6 GPS UART support module") +set (module_src ${libname}.cxx) +set (module_h ${libname}.h) +upm_module_init() diff --git a/src/ublox6/jsupm_ublox6.i b/src/ublox6/jsupm_ublox6.i new file mode 100644 index 00000000..12c75528 --- /dev/null +++ b/src/ublox6/jsupm_ublox6.i @@ -0,0 +1,13 @@ +%module jsupm_ublox6 +%include "../upm.i" +%include "stdint.i" +%include "carrays.i" + +%{ + #include "ublox6.h" + speed_t int_B9600 = B9600; +%} + +%include "ublox6.h" +speed_t int_B9600 = B9600; +%array_class(char, charArray); diff --git a/src/ublox6/pyupm_ublox6.i b/src/ublox6/pyupm_ublox6.i new file mode 100644 index 00000000..ab321805 --- /dev/null +++ b/src/ublox6/pyupm_ublox6.i @@ -0,0 +1,9 @@ +%module pyupm_ublox6 +%include "../upm.i" + +%feature("autodoc", "3"); + +%include "ublox6.h" +%{ + #include "ublox6.h" +%} diff --git a/src/ublox6/ublox6.cxx b/src/ublox6/ublox6.cxx new file mode 100644 index 00000000..ccb4d4fc --- /dev/null +++ b/src/ublox6/ublox6.cxx @@ -0,0 +1,140 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2014 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "ublox6.h" + +using namespace upm; +using namespace std; + +Ublox6::Ublox6(int uart, const char *tty) : + m_ttyFd(-1) +{ + mraa_init(); + + if ( !(m_uart = mraa_uart_init(uart)) ) + { + cerr << __FUNCTION__ << ": mraa_uart_init() failed" << endl; + return; + } + + // now open the tty + if ( (m_ttyFd = open(tty, O_RDWR)) == -1) + { + cerr << __FUNCTION__ << ": open of " << tty << " failed: " + << strerror(errno) << endl; + return; + } +} + +Ublox6::~Ublox6() +{ + if (m_ttyFd != -1) + close(m_ttyFd); +} + +bool Ublox6::dataAvailable() +{ + if (m_ttyFd == -1) + return false; + + struct timeval timeout; + + // no waiting + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + int nfds; + fd_set readfds; + + FD_ZERO(&readfds); + + FD_SET(m_ttyFd, &readfds); + + if (select(m_ttyFd + 1, &readfds, NULL, NULL, &timeout) > 0) + return true; // data is ready + else + return false; +} + +int Ublox6::readData(char *buffer, size_t len) +{ + if (m_ttyFd == -1) + return(-1); + + int rv = read(m_ttyFd, buffer, len); + + if (rv < 0) + cerr << __FUNCTION__ << ": read failed: " << strerror(errno) << endl; + + return rv; +} + +int Ublox6::writeData(char * buffer, size_t len) +{ + if (m_ttyFd == -1) + return(-1); + + int rv = write(m_ttyFd, buffer, len); + + if (rv < 0) + { + cerr << __FUNCTION__ << ": write failed: " << strerror(errno) << endl; + return rv; + } + + tcdrain(m_ttyFd); + + return rv; +} + +bool Ublox6::setupTty(speed_t baud) +{ + if (m_ttyFd == -1) + return(false); + + struct termios termio; + + // get current modes + tcgetattr(m_ttyFd, &termio); + + // setup for a 'raw' mode. 81N, no echo or special character + // handling, such as flow control. + cfmakeraw(&termio); + + // set our baud rates + cfsetispeed(&termio, baud); + cfsetospeed(&termio, baud); + + // make it so + int rv; + if ( (rv = tcsetattr(m_ttyFd, TCSAFLUSH, &termio)) < 0) + { + cerr << __FUNCTION__ << ": tcsetattr failed: " << strerror(errno) << endl; + return false; + } + + return true; +} diff --git a/src/ublox6/ublox6.h b/src/ublox6/ublox6.h new file mode 100644 index 00000000..885aff8e --- /dev/null +++ b/src/ublox6/ublox6.h @@ -0,0 +1,117 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2014 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +const int UBLOX6_DEFAULT_UART = 0; + +namespace upm { + + /** + * @brief C++ API for the U-BLOX 6 GPS module + * + * UPM support for the U-BLOX 6 GPS Module + * + * @ingroup grove uart + * @snippet ublox6.cxx Interesting + */ + class Ublox6 { + public: + /** + * U-BLOX 6 GPS module constructor + * + * @param uart defualt uart to use (0 or 1) + * @param tty tty device to use + */ + Ublox6(int uart, const char *tty); + + /** + * U-BLOX 6 GPS module Destructor + */ + ~Ublox6(); + + /** + * Check to see if there is data available for reading + * + * @return true if there is data available to be read + */ + bool dataAvailable(); + + /** + * read any available data into a user-supplied buffer. Note, the + * call will block until data is available to be read. Use + * dataAvailable() to determine whether there is data available + * beforehand, to avoid blocking. + * + * @param buffer the buffer to hold the data read + * @param len the length of the buffer + * @return the number of bytes read + */ + int readData(char *buffer, size_t len); + + /** + * write the data in buffer to the device + * + * @param buffer the buffer to hold the data read + * @param len the length of the buffer + * @return the number of bytes written + */ + int writeData(char *buffer, size_t len); + + /** + * setup the proper tty i/o modes and the baudrate. The default + * baud rate is 9600 (B9600). + * + * @param baud the desired baud rate. + * @return true if successful + */ + bool setupTty(speed_t baud=B9600); + + protected: + int ttyFd() { return m_ttyFd; }; + int setTtyFd(int fd) { m_ttyFd = fd; }; + + private: + mraa_uart_context m_uart; + int m_ttyFd; + }; +} + +