nmea_gps: add support for ubloc I2c reading of NMEA data
These changes allow NMEA data to be read via I2C on UBLOX compliant devices that support this capability, such as the LEA-6H based GPS shield from DFRobot. It adds a new init() function to the C code, and a new constructor to the C++ code. It also adds 5 new examples for C, C++, Javascript, Python, and Java. Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
@@ -29,6 +29,45 @@
|
||||
|
||||
#include "upm_utilities.h"
|
||||
|
||||
// For ublox6 and compatible I2C communications (see the u-blox6
|
||||
// Receiver Description Protocol Specification datasheet for details).
|
||||
|
||||
#define UBLOX6_I2C_BYTES_AVAIL_H 0xfd
|
||||
#define UBLOX6_I2C_BYTES_AVAIL_L 0xfe
|
||||
#define UBLOX6_I2C_BYTE_STREAM 0xff
|
||||
|
||||
#define UBLOX6_I2C_BYTE_NONE 0xff // read if no data avail
|
||||
|
||||
// static helpers for i2c reading
|
||||
static uint8_t readReg(const nmea_gps_context dev, uint8_t reg)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
assert(dev->i2c != NULL);
|
||||
|
||||
int rv;
|
||||
if ((rv = mraa_i2c_read_byte_data(dev->i2c, reg)) < 0)
|
||||
printf("%s: mraa_i2c_read_byte_data() failed.\n", __FUNCTION__);
|
||||
|
||||
// This will return 0xff on errors, which is invalid NMEA data anyway.
|
||||
return (uint8_t)rv;
|
||||
}
|
||||
|
||||
static int readRegs(const nmea_gps_context dev, uint8_t reg,
|
||||
uint8_t *buffer, int len)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
assert(dev->i2c != NULL);
|
||||
|
||||
int rv;
|
||||
if ((rv = mraa_i2c_read_bytes_data(dev->i2c, reg, buffer, len)) < 0)
|
||||
{
|
||||
printf("%s: mraa_i2c_read_bytes_data() failed.\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// uart init
|
||||
nmea_gps_context nmea_gps_init(unsigned int uart, unsigned int baudrate,
|
||||
int enable_pin)
|
||||
{
|
||||
@@ -42,6 +81,7 @@ nmea_gps_context nmea_gps_init(unsigned int uart, unsigned int baudrate,
|
||||
memset((void *)dev, 0, sizeof(struct _nmea_gps_context));
|
||||
|
||||
dev->uart = NULL;
|
||||
dev->i2c = NULL;
|
||||
dev->gpio_en = NULL;
|
||||
|
||||
// initialize the MRAA contexts
|
||||
@@ -82,6 +122,51 @@ nmea_gps_context nmea_gps_init(unsigned int uart, unsigned int baudrate,
|
||||
return dev;
|
||||
}
|
||||
|
||||
// i2c ublox init
|
||||
nmea_gps_context nmea_gps_init_ublox_i2c(unsigned int bus, uint8_t addr)
|
||||
{
|
||||
nmea_gps_context dev =
|
||||
(nmea_gps_context)malloc(sizeof(struct _nmea_gps_context));
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
// zero out context
|
||||
memset((void *)dev, 0, sizeof(struct _nmea_gps_context));
|
||||
|
||||
dev->uart = NULL;
|
||||
dev->i2c = NULL;
|
||||
dev->gpio_en = NULL;
|
||||
|
||||
// initialize the MRAA contexts
|
||||
|
||||
if (!(dev->i2c = mraa_i2c_init(bus)))
|
||||
{
|
||||
printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__);
|
||||
nmea_gps_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This device cannot operate at more than 100Khz, so we set that
|
||||
// here and bail if it fails.
|
||||
|
||||
if (mraa_i2c_frequency(dev->i2c, MRAA_I2C_STD))
|
||||
{
|
||||
printf("%s: mraa_i2c_frequency(MRAA_I2C_STD) failed.\n", __FUNCTION__);
|
||||
nmea_gps_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mraa_i2c_address(dev->i2c, addr))
|
||||
{
|
||||
printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__);
|
||||
nmea_gps_close(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void nmea_gps_close(nmea_gps_context dev)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
@@ -91,6 +176,8 @@ void nmea_gps_close(nmea_gps_context dev)
|
||||
|
||||
if (dev->uart)
|
||||
mraa_uart_stop(dev->uart);
|
||||
if (dev->i2c)
|
||||
mraa_i2c_stop(dev->i2c);
|
||||
if (dev->gpio_en)
|
||||
mraa_gpio_close(dev->gpio_en);
|
||||
|
||||
@@ -116,6 +203,35 @@ int nmea_gps_read(const nmea_gps_context dev, char *buffer, size_t len)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
// i2c ublox
|
||||
if (dev->i2c)
|
||||
{
|
||||
int rv;
|
||||
if ((rv = readRegs(dev, UBLOX6_I2C_BYTE_STREAM, buffer, len)) < 0)
|
||||
return rv;
|
||||
|
||||
// now we need to go through the bytes returned, and stop
|
||||
// counting "real" bytes when we hit any character with the high
|
||||
// bit set. The documentation implies that only a 0xff will be
|
||||
// sent when no new data is available, but it seems sometimes
|
||||
// the return contains 0xbf and 0xc3 bytes. So we stop counting
|
||||
// as soon as we see any "8 bit" character (which isn't allowed
|
||||
// by NMEA anyway).
|
||||
int realBytes = 0;
|
||||
int i;
|
||||
|
||||
for (i=0; i<rv; i++)
|
||||
{
|
||||
if (buffer[i] & 0x80)
|
||||
break;
|
||||
|
||||
realBytes++;
|
||||
}
|
||||
|
||||
return realBytes;
|
||||
}
|
||||
|
||||
// uart
|
||||
return mraa_uart_read(dev->uart, buffer, len);
|
||||
}
|
||||
|
||||
@@ -123,6 +239,9 @@ int nmea_gps_write(const nmea_gps_context dev, char *buffer, size_t len)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
if (!dev->uart)
|
||||
return UPM_ERROR_NO_RESOURCES;
|
||||
|
||||
return mraa_uart_write(dev->uart, buffer, len);
|
||||
}
|
||||
|
||||
@@ -130,6 +249,24 @@ bool nmea_gps_data_available(const nmea_gps_context dev, unsigned int millis)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
// i2c ublox
|
||||
if (dev->i2c)
|
||||
{
|
||||
// here millis is ignored
|
||||
uint8_t h, l;
|
||||
|
||||
h = readReg(dev, UBLOX6_I2C_BYTES_AVAIL_H);
|
||||
l = readReg(dev, UBLOX6_I2C_BYTES_AVAIL_L);
|
||||
|
||||
uint16_t total = (h << 8) | l;
|
||||
// 0 means no data available, 0xffff means read errors
|
||||
if (total == 0x0000 || total == 0xffff)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// uart
|
||||
if (mraa_uart_data_available(dev->uart, millis))
|
||||
return true;
|
||||
else
|
||||
@@ -141,6 +278,9 @@ upm_result_t nmea_gps_set_baudrate(const nmea_gps_context dev,
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
if (!dev->uart)
|
||||
return UPM_ERROR_NO_RESOURCES;
|
||||
|
||||
if (mraa_uart_set_baudrate(dev->uart, baudrate))
|
||||
{
|
||||
printf("%s: mraa_uart_set_baudrate() failed.\n", __FUNCTION__);
|
||||
|
||||
Reference in New Issue
Block a user