Skip to content

Commit 1479fb6

Browse files
committed
Add support for DDC mode (over I2C)
1 parent c9f2de8 commit 1479fb6

File tree

5 files changed

+266
-29
lines changed

5 files changed

+266
-29
lines changed

keywords.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ wakeup KEYWORD2
3131
########################################
3232
# Constants
3333
########################################
34+
35+
GPS_MODE_UART LITERAL1
36+
GPS_MODE_I2C LITERAL1

src/GPS.cpp

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@ extern "C" {
3030
#define GPS_MASK_RMC 0x01
3131
#define GPS_MASK_GGA 0x02
3232

33-
GPSClass::GPSClass(HardwareSerial& serial, unsigned long baudrate, int extintPin) :
33+
GPSClass::GPSClass(HardwareSerial& serial, unsigned long baudrate, SerialDDC& serialDDC, unsigned long clockrate, int extintPin) :
3434
_serial(&serial),
3535
_baudrate(baudrate),
36+
_serialDDC(&serialDDC),
37+
_clockRate(clockrate),
3638
_extintPin(extintPin)
3739
{
3840
}
@@ -41,12 +43,26 @@ GPSClass::~GPSClass()
4143
{
4244
}
4345

44-
int GPSClass::begin()
46+
int GPSClass::begin(int mode)
4547
{
48+
_mode = mode;
49+
4650
pinMode(_extintPin, OUTPUT);
4751
digitalWrite(_extintPin, HIGH);
52+
delay(100); // delay for GPS to wakeup
53+
54+
if (_mode == GPS_MODE_UART) {
55+
_serial->begin(_baudrate);
56+
_stream = _serial;
57+
} else {
58+
if (!_serialDDC->begin(_clockRate)) {
59+
end();
4860

49-
_serial->begin(_baudrate);
61+
return 0;
62+
}
63+
64+
_stream = _serialDDC;
65+
}
5066

5167
_available = 0;
5268
_index = 0;
@@ -56,10 +72,14 @@ int GPSClass::begin()
5672

5773
void GPSClass::end()
5874
{
59-
_serial->end();
60-
6175
digitalWrite(_extintPin, LOW);
6276
pinMode(_extintPin, INPUT);
77+
78+
if (_mode == GPS_MODE_UART) {
79+
_serial->end();
80+
} else {
81+
_serialDDC->end();
82+
}
6383
}
6484

6585
int GPSClass::available()
@@ -143,7 +163,12 @@ void GPSClass::standby()
143163

144164
sendUbx(0x06, 0x3b, payload, sizeof(payload));
145165

146-
_serial->end();
166+
if (_mode == GPS_MODE_UART) {
167+
_serial->end();
168+
} else {
169+
_serialDDC->end();
170+
}
171+
147172
digitalWrite(_extintPin, LOW);
148173

149174
_available = 0;
@@ -152,18 +177,23 @@ void GPSClass::standby()
152177

153178
void GPSClass::wakeup()
154179
{
155-
_serial->begin(_baudrate);
156-
157180
digitalWrite(_extintPin, HIGH);
181+
delay(100); // delay for GPS to wakeup
182+
183+
if (_mode == GPS_MODE_UART) {
184+
_serial->begin(_baudrate);
185+
} else {
186+
_serialDDC->begin(_clockRate);
187+
}
158188

159189
_available = 0;
160190
_index = 0;
161191
}
162192

163193
void GPSClass::poll()
164194
{
165-
if (_serial->available()) {
166-
char c = _serial->read();
195+
if (_stream->available()) {
196+
char c = _stream->read();
167197

168198
#ifdef GPS_DEBUG
169199
Serial.print(c);
@@ -232,27 +262,29 @@ void GPSClass::sendUbx(uint8_t cls, uint8_t id, uint8_t payload[], uint16_t leng
232262
{
233263
uint8_t ckA = 0;
234264
uint8_t ckB = 0;
235-
uint8_t prefix[] = { cls, id, (uint8_t)(length & 0xff), (uint8_t)(length >> 8) };
236265

237-
for (unsigned int i = 0; i < sizeof(prefix); i++) {
238-
ckA += prefix[i];
239-
ckB += ckA;
240-
}
266+
unsigned int cmdLength = 8 + length;
267+
uint8_t cmd[cmdLength];
241268

242-
for (unsigned int i = 0; i < length; i++) {
243-
ckA += payload[i];
269+
cmd[0] = 0xb5;
270+
cmd[1] = 0x62;
271+
cmd[2] = cls;
272+
cmd[3] = id;
273+
cmd[4] = (length & 0xff);
274+
cmd[5] = (length >> 8);
275+
memcpy(&cmd[6], payload, length);
276+
277+
// calculate checksum, start at index 2 and up to the payload
278+
for (unsigned int i = 2; i < (cmdLength - 2); i++) {
279+
ckA += cmd[i];
244280
ckB += ckA;
245281
}
246282

247-
_serial->write(0xb5);
248-
_serial->write(0x62);
249-
_serial->write(cls);
250-
_serial->write(id);
251-
_serial->write((uint8_t*)&length, sizeof(length));
252-
_serial->write(payload, length);
253-
_serial->write(ckA);
254-
_serial->write(ckB);
255-
_serial->flush();
283+
cmd[cmdLength - 2] = ckA;
284+
cmd[cmdLength - 1] = ckB;
285+
286+
_stream->write(cmd, cmdLength);
287+
_stream->flush();
256288
}
257289

258290
float GPSClass::toDegrees(float f)
@@ -263,4 +295,5 @@ float GPSClass::toDegrees(float f)
263295
return (degrees + (minutes / 60.0));
264296
}
265297

266-
GPSClass GPS(Serial1, 9600, 7);
298+
static SerialDDC serialDDC(Wire, 0x42, 0xfd, 0xff);
299+
GPSClass GPS(Serial1, 9600, serialDDC, 400000, 7);

src/GPS.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@
2222

2323
#include <Arduino.h>
2424

25+
#include "utility/SerialDDC.h"
26+
27+
enum
28+
{
29+
GPS_MODE_UART,
30+
GPS_MODE_I2C,
31+
};
32+
2533
class GPSClass {
2634
public:
27-
GPSClass(HardwareSerial& serial, unsigned long baudrate, int extintPin);
35+
GPSClass(HardwareSerial& serial, unsigned long baudrate, SerialDDC& serialDDC, unsigned long clockrate, int extintPin);
2836
virtual ~GPSClass();
2937

30-
int begin();
38+
int begin(int mode = GPS_MODE_I2C);
3139
void end();
3240

3341
int available();
@@ -55,8 +63,15 @@ class GPSClass {
5563
private:
5664
HardwareSerial* _serial;
5765
unsigned long _baudrate;
66+
67+
SerialDDC* _serialDDC;
68+
unsigned long _clockRate;
69+
5870
int _extintPin;
5971

72+
int _mode;
73+
Stream* _stream;
74+
6075
int _available;
6176
char _buffer[82 + 1];
6277
int _index;

src/utility/SerialDDC.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
This file is part of the Arduino_MKRGPS library.
3+
Copyright (c) 2019 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "SerialDDC.h"
21+
22+
SerialDDC::SerialDDC(TwoWire& wire, int address, uint8_t availableRegister, uint8_t readRegister) :
23+
_wire(&wire),
24+
_address(address),
25+
_availableRegister(availableRegister),
26+
_readRegister(readRegister)
27+
{
28+
}
29+
30+
SerialDDC::~SerialDDC()
31+
{
32+
}
33+
34+
int SerialDDC::begin(uint32_t clockFrequency)
35+
{
36+
_wire->begin();
37+
_wire->setClock(clockFrequency);
38+
39+
_wire->beginTransmission(_address);
40+
if (_wire->endTransmission() != 0) {
41+
// failure
42+
end();
43+
44+
return 0;
45+
}
46+
47+
return 1;
48+
}
49+
50+
void SerialDDC::end()
51+
{
52+
_wire->end();
53+
}
54+
55+
int SerialDDC::available()
56+
{
57+
int avail = _wire->available();
58+
59+
if (avail) {
60+
return avail;
61+
}
62+
63+
_wire->beginTransmission(_address);
64+
_wire->write(_availableRegister);
65+
if (_wire->endTransmission(false) != 0) {
66+
return 0;
67+
}
68+
69+
if (_wire->requestFrom(_address, 2) != 2) {
70+
return 0;
71+
}
72+
73+
uint8_t availableHigh = _wire->read();
74+
uint8_t availableLow = _wire->read();
75+
76+
if (availableHigh == 0xff && availableLow == 0xff) {
77+
return 0;
78+
}
79+
80+
avail = (availableHigh << 8) | availableLow;
81+
82+
if (avail > 255) {
83+
avail = 255;
84+
}
85+
86+
_wire->beginTransmission(_address);
87+
_wire->write(_readRegister);
88+
if (_wire->endTransmission(false) != 0) {
89+
return 0;
90+
}
91+
92+
if (_wire->requestFrom(_address, avail) != avail) {
93+
return 0;
94+
}
95+
96+
return _wire->available();
97+
}
98+
99+
int SerialDDC::read()
100+
{
101+
return _wire->read();
102+
}
103+
104+
int SerialDDC::peek()
105+
{
106+
return _wire->peek();
107+
}
108+
109+
size_t SerialDDC::write(uint8_t b)
110+
{
111+
return write(&b, sizeof(b));
112+
}
113+
114+
size_t SerialDDC::write(const uint8_t *buffer, size_t size)
115+
{
116+
if (size < 2) {
117+
return 0;
118+
}
119+
120+
int result;
121+
122+
_wire->beginTransmission(_address);
123+
result = _wire->write(buffer, size);
124+
if (_wire->endTransmission() != 0) {
125+
return 0;
126+
}
127+
128+
return result;
129+
}
130+
131+
void SerialDDC::flush()
132+
{
133+
// no-op
134+
}

src/utility/SerialDDC.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
This file is part of the Arduino_MKRGPS library.
3+
Copyright (c) 2019 Arduino SA. All rights reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef _SERIAL_DDC_H_
21+
#define _SERIAL_DDC_H_
22+
23+
#include <Arduino.h>
24+
25+
#include <Wire.h>
26+
27+
class SerialDDC : public Stream {
28+
public:
29+
SerialDDC(TwoWire& wire, int address, uint8_t availableRegister, uint8_t readRegister);
30+
virtual ~SerialDDC();
31+
32+
int begin(uint32_t clockFrequency);
33+
void end();
34+
35+
// from Stream
36+
virtual int available();
37+
virtual int read();
38+
virtual int peek();
39+
40+
// from Print
41+
virtual size_t write(uint8_t);
42+
virtual size_t write(const uint8_t *buffer, size_t size);
43+
virtual void flush();
44+
45+
private:
46+
TwoWire* _wire;
47+
int _address;
48+
uint8_t _availableRegister;
49+
uint8_t _readRegister;
50+
};
51+
52+
#endif

0 commit comments

Comments
 (0)