Skip to content

Commit 73f11be

Browse files
committed
Get cru document format working
1 parent 1156c05 commit 73f11be

File tree

7 files changed

+244
-50
lines changed

7 files changed

+244
-50
lines changed

docs/drive_format.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,39 @@ All drives are stored in a custom binary format to save space. The header will a
44
## Version 1:
55
## Packet format
66
```
7-
|------Header------|------n drive frames------|------final drive frames (all bits set to 1)------|------Footer------|
8-
20 bytes n frames * 67 bytes 67 bytes 1 byte
7+
|------Header------|------Polyline------|------drive frames------|------Footer------|
8+
28 bytes int8_t*Polyline Size n frames * 14 bytes 1 byte
99
```
1010

1111
### Header:
1212
```
13-
|------Version------|------VIN------|------Fuel tank level------|
14-
uint16_t int8_t * 17 uint8_t
13+
|------Version------|------VIN------|------Fuel tank level------|------Polyline Size------|------Drive Frame Size------|
14+
uint16_t int8_t * 17 uint8_t uint32_t uint32_t
1515
```
1616
- Version: 16 bit unsigned integer to allow clients to correctly parse the data
17-
- VIN: A 17 character ascii string representing the vehicle VIN
17+
- VIN: A 17 character ascii string representing the vehicle VIN. **Not** null terminated
1818
- Fuel tank level: 8 bit unsigned integer representing the vehicle fuel tank level at the start of the drive, a percentage between 0 and 100 (inclusive)
19+
- Polyline Size: The length of the polyline string. Each element of the polyline string is int8_t
20+
- Drive Frame Size: The size of the drive frame buffer. Each frame is divided into 14 bytes, so n_frames = drive frame size / 14
21+
1922

2023
### Drive frame:
21-
Each frame represents the vehicle state at a particular point in time. The final drive frame will have all bits set to 1 and is considered a stop frame and is therefore invalid.
24+
Each frame represents the vehicle state at a particular point in time.
2225
```
23-
|-----GPS Time-----|-----GPS Speed-----|-----Latitutde-----|-----Longitude-----|-----Heading-----|-----Altitude-----|-----AccelX-----|-----AccelY-----|-----AccelZ-----|-----Vehicle Speed-----|
24-
uint64_t float (4 byte) float (4 byte) float (4 byte) uint16_t float (4 byte) float (4 byte) float (4 byte) float (4 byte) uint8_t
26+
|-----GPS Time-----|-----GPS Speed-----|-----Heading-----|-----Altitude-----|-----Vehicle Speed-----|
27+
uint64_t uint8_t int16_t int16_t uint8_t
2528
```
2629
- GPS Time: a 64 bit unsigned integer representing the unix time of the data frame
2730
- GPS Speed: a 64 bit float representing the GPS speed in km/h
28-
- GPS latitude: a 64 bit float representing the GPS latitude
29-
- GPS longtitude: a 64 bit float representing the GPS longitude
3031
- GPS heading: a 16 bit unsigned integer representing the GPS heading
3132
- GPS altitude: a 64 bit float representing the GPS heading
32-
- AccelX: a 64 bit float representing the acceleration of the device in the x axis
33-
- AccelY: a 64 bit float representing the acceleration of the device in the y axis
34-
- AccelZ: a 64 bit float representing the acceleration of the device in the z axis
3533
- Vehicle Speed: an 8 bit unsigned integer representing the vehicle speed as reported by OBD
3634

3735

36+
### Polyline data:
37+
To save space, all longitude and latitude data is compressed with the polyline encoding format as a base64 string. Every drive frame will have a corresponding lat/long.
38+
The polyline string is **not** null terminated and the size must be determined with the polyline size information.
39+
3840
## Footer:
3941
```
4042
|------Fuel tank level------|

include/Carduino+Drive.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef _CARDUINO_DEVICE_H
2+
#define _CARDUINO_DEVICE_H
3+
#include <FreematicsPlus.h>
4+
#include "polylineencoder.h"
5+
6+
class Carduino_Drive {
7+
8+
public:
9+
/**
10+
* Create an instance of a drive
11+
*/
12+
Carduino_Drive(char vin[17], uint8_t startFuelLevel, time_t startTime);
13+
14+
/**
15+
* Destructor
16+
*/
17+
~Carduino_Drive();
18+
19+
void addFrame(time_t time, uint8_t gpsSpeed, int32_t latitude,
20+
int32_t longitude,
21+
int16_t heading, int16_t altitude,
22+
uint8_t vehicleSpeed);
23+
24+
25+
void getDriveData(int8_t **data, size_t *size, uint8_t finalFuelTankLevel);
26+
time_t startTime;
27+
28+
private:
29+
gepaf::PolylineEncoder<> encoder;
30+
int bufferCapacity;
31+
int bufferSize;
32+
int8_t *buffer;
33+
char vin[17];
34+
uint8_t startFuelLevel;
35+
};
36+
#endif

include/Carduino+OBD.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <FreematicsPlus.h>
44
#include "Carduino+Accelerometer.h"
55

6+
#define OBD_RECV_BUF_SIZE 80
7+
68
class Carduino_OBD {
79

810
public:
@@ -19,9 +21,14 @@ class Carduino_OBD {
1921

2022

2123
bool isConnected();
24+
25+
char vinBuffer[OBD_RECV_BUF_SIZE + 1];
26+
27+
uint8_t getVehicleSpeed();
2228
private:
2329
Carduino_Accelerometer *accelerometerUnit;
2430
bool connected;
31+
uint8_t vehicleSpeed;
2532
};
2633

2734

include/Carduino+SD.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CStorage {
4545
virtual uint16_t samples() {
4646
return m_samples;
4747
}
48-
virtual void dispatch(const char *buf, byte len) {
48+
virtual void dispatch(const char *buf, size_t len) {
4949
// output data via serial
5050
Serial.write((uint8_t *)buf, len);
5151
Serial.write(' ');
@@ -89,7 +89,7 @@ class CStorageRAM: public CStorage {
8989
char *buffer() {
9090
return m_cache;
9191
}
92-
void dispatch(const char *buf, byte len) {
92+
void dispatch(const char *buf, size_t len) {
9393
// reserve some space for checksum
9494
int remain = m_cacheSize - m_cacheBytes - len - 3;
9595
if (remain < 0) {
@@ -129,7 +129,7 @@ class FileLogger : public CStorage {
129129
FileLogger() {
130130
m_delimiter = ',';
131131
}
132-
virtual void dispatch(const char *buf, byte len) {
132+
virtual void dispatch(const char *buf, size_t len) {
133133
if(!open) return;
134134

135135
if (m_file.write((uint8_t *)buf, len) != len) {

src/Carduino+Drive.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#include "Carduino+Drive.h"
2+
3+
const int HEADER_SIZE = 28;
4+
const int DRIVE_FRAME_SIZE = 14;
5+
const int FOOTER_SIZE = 1;
6+
const uint16_t VERSION = 1;
7+
8+
Carduino_Drive::Carduino_Drive(char vin[], uint8_t startFuelLevel,
9+
time_t startTime) {
10+
this->bufferCapacity = DRIVE_FRAME_SIZE * 200; //Start with 200 drive frames
11+
this->bufferSize = 0;
12+
13+
this->buffer = (int8_t *)(malloc(this->bufferCapacity));
14+
15+
memcpy(this->vin, vin, 17);
16+
17+
this->startFuelLevel = startFuelLevel;
18+
this->startTime = startTime;
19+
}
20+
21+
Carduino_Drive::~Carduino_Drive() {
22+
free(this->buffer);
23+
}
24+
25+
void Carduino_Drive::addFrame(time_t time, uint8_t gpsSpeed, int32_t latitude,
26+
int32_t longitude,
27+
int16_t heading, int16_t altitude,
28+
uint8_t vehicleSpeed) {
29+
this->encoder.addPoint(latitude, longitude);
30+
/*
31+
|-----GPS Time-----|-----GPS Speed-----|-----Heading-----|-----Altitude-----|-----Vehicle Speed-----|
32+
uint64_t uint8_t int16_t int16_t uint8_t
33+
*/
34+
35+
if (this->bufferCapacity == this->bufferSize) {
36+
// Allocate another 200 drive frames
37+
int newCapacity = this->bufferCapacity + DRIVE_FRAME_SIZE * 200;
38+
this->buffer = (int8_t *)(realloc(this->buffer, newCapacity));
39+
this->bufferCapacity = newCapacity;
40+
}
41+
42+
this->buffer[this->bufferSize + 0] = (uint8_t)(time & 0xff);
43+
this->buffer[this->bufferSize + 1] = (uint8_t)(time >> 8) & 0xff;
44+
this->buffer[this->bufferSize + 2] = (uint8_t)(time >> 16) & 0xff;
45+
this->buffer[this->bufferSize + 3] = (uint8_t)(time >> 24) & 0xff;
46+
this->buffer[this->bufferSize + 4] = (uint8_t)(time >> 32) & 0xff;
47+
this->buffer[this->bufferSize + 5] = (uint8_t)(time >> 40) & 0xff;
48+
this->buffer[this->bufferSize + 6] = (uint8_t)(time >> 48) & 0xff;
49+
this->buffer[this->bufferSize + 7] = (uint8_t)(time >> 56) & 0xff;
50+
51+
this->buffer[this->bufferSize + 8] = gpsSpeed;
52+
53+
this->buffer[this->bufferSize + 9] = (uint8_t)(heading & 0xff);
54+
this->buffer[this->bufferSize + 10] = (uint8_t)(heading >> 8);
55+
56+
this->buffer[this->bufferSize + 11] = (uint8_t)(altitude & 0xff);
57+
this->buffer[this->bufferSize + 12] = (uint8_t)(altitude >> 8);
58+
59+
this->buffer[this->bufferSize + 13] = vehicleSpeed;
60+
61+
this->bufferSize += DRIVE_FRAME_SIZE;
62+
63+
64+
Serial.print("Buffer size: ");
65+
Serial.print(bufferSize);
66+
Serial.println();
67+
68+
}
69+
70+
71+
void Carduino_Drive::getDriveData(int8_t **data, size_t *size,
72+
uint8_t finalFuelTankLevel) {
73+
74+
std::string polyline = this->encoder.encode();
75+
uint32_t polyLineCount = polyline.length();
76+
77+
size_t dataSize = HEADER_SIZE + polyLineCount + this->bufferSize + FOOTER_SIZE;
78+
79+
*data = (int8_t *)(malloc(dataSize));
80+
*size = dataSize;
81+
82+
83+
Serial.print("data size: ");
84+
Serial.print(dataSize);
85+
Serial.println();
86+
87+
data[0][0] = (uint8_t)(VERSION & 0xff);
88+
data[0][1] = (uint8_t)(VERSION >> 8);
89+
90+
memcpy((data[0] + 2), this->vin, 17);
91+
92+
data[0][19] = this->startFuelLevel;
93+
94+
data[0][20] = (uint8_t)(polyLineCount & 0xff);
95+
data[0][21] = (uint8_t)(polyLineCount >> 8) & 0xff;
96+
data[0][22] = (uint8_t)(polyLineCount >> 16) & 0xff;
97+
data[0][23] = (uint8_t)(polyLineCount >> 24);
98+
99+
data[0][24] = (uint8_t)(this->bufferSize & 0xff);
100+
data[0][25] = (uint8_t)(this->bufferSize >> 8) & 0xff;
101+
data[0][26] = (uint8_t)(this->bufferSize >> 16) & 0xff;
102+
data[0][27] = (uint8_t)(this->bufferSize >> 24);
103+
104+
105+
memcpy((data[0] + 28), polyline.c_str(), polyLineCount);
106+
memcpy((data[0] + 28 + polyLineCount), this->buffer, this->bufferSize);
107+
108+
109+
data[0][28 + this->bufferSize + polyLineCount] = finalFuelTankLevel;
110+
}

src/Carduino+DriveManager.cpp

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
#include <FreematicsPlus.h>
99
#include "Carduino+DriveManager.h"
10-
#include "polylineencoder.h"
10+
#include "Carduino+Drive.h"
1111
#define OBD_RECV_BUF_SIZE 80
1212

1313

@@ -56,32 +56,14 @@ Carduino_DriveManager::Carduino_DriveManager(Carduino_GPS *gpsUnit,
5656

5757
unsigned long lastSaveTime = 0;
5858
uint32_t lastGPSSavetime = 0;
59-
60-
gepaf::PolylineEncoder<> encoder;
6159
SDLogger logger;
6260

6361
bool hasSaved = false;
6462
bool hasConnected = false;
6563

66-
void Carduino_DriveManager::runLoop(void) {
67-
68-
char timeBuf[32];
69-
sprintf(timeBuf, "%02u:%02u:%02u",
70-
this->gpsUnit->gd->time / 1000000, (this->gpsUnit->gd->time % 1000000) / 10000,
71-
(this->gpsUnit->gd->time % 10000) / 100);
72-
73-
char dateBuf[32];
74-
sprintf(dateBuf, "%02u/%02u/%02u", (this->gpsUnit->gd->date % 1000000) / 10000,
75-
(this->gpsUnit->gd->date % 10000) / 100, this->gpsUnit->gd->date % 100);
76-
77-
struct std::tm tm;
78-
std::stringstream ss;
79-
ss << timeBuf << " " << dateBuf << " +0";
80-
strptime(ss.str().c_str(), "%H:%M:%S %d/%m/%y %z", &tm);
81-
std::time_t time = timegm(&tm);
64+
Carduino_Drive *currentDrive = NULL;
8265

83-
84-
return;
66+
void Carduino_DriveManager::runLoop(void) {
8567

8668
//millis() rolls over after 50 days so take the abs
8769
if(abs(millis() - lastSaveTime) > 7000 && this->obdUnit->isConnected()) {
@@ -93,27 +75,79 @@ void Carduino_DriveManager::runLoop(void) {
9375
Serial.println(" No GPS, returning");
9476
return;
9577
}
78+
79+
if (this->gpsUnit->gd->lat == 0 || this->gpsUnit->gd->lng == 0) {
80+
Serial.println(" GPS coordinates 0, returning");
81+
return;
82+
}
83+
84+
char timeBuf[32];
85+
sprintf(timeBuf, "%02u:%02u:%02u",
86+
this->gpsUnit->gd->time / 1000000, (this->gpsUnit->gd->time % 1000000) / 10000,
87+
(this->gpsUnit->gd->time % 10000) / 100);
88+
89+
char dateBuf[32];
90+
sprintf(dateBuf, "%02u/%02u/%02u", (this->gpsUnit->gd->date % 1000000) / 10000,
91+
(this->gpsUnit->gd->date % 10000) / 100, this->gpsUnit->gd->date % 100);
92+
93+
struct std::tm tm;
94+
std::stringstream ss;
95+
ss << timeBuf << " " << dateBuf << " +0";
96+
strptime(ss.str().c_str(), "%H:%M:%S %d/%m/%y %z", &tm);
97+
std::time_t time = timegm(&tm);
98+
99+
if(currentDrive == NULL) {
100+
//TODO: Get the actual fuel level
101+
currentDrive = new Carduino_Drive(this->obdUnit->vinBuffer, 100,
102+
time);
103+
}
104+
96105
hasSaved = false;
97106
lastGPSSavetime = this->gpsUnit->gd->time;
98107

99-
encoder.addPoint(this->gpsUnit->gd->lat, this->gpsUnit->gd->lng);
108+
/*
109+
void addFrame(uint32_t time, uint8_t gpsSpeed, int32_t latitude,
110+
int32_t longitude,
111+
int16_t heading, int16_t altitude,
112+
uint8_t vehicleSpeed);
113+
*/
114+
115+
//TODO: get actual vehicle speed
116+
currentDrive->addFrame(time, this->gpsUnit->gd->speed * 1852 / 1000,
117+
this->gpsUnit->gd->lat, this->gpsUnit->gd->lng, this->gpsUnit->gd->heading,
118+
this->gpsUnit->gd->alt, this->obdUnit->getVehicleSpeed());
100119

101120
lastSaveTime = millis();
102121
}
103122

104123
if(!this->obdUnit->isConnected() && !hasSaved && hasConnected) {
105124
Serial.println("Attempting save");
106125
logger.init();
107-
int fileid = logger.begin("name");
108126

109-
std::string res = encoder.encode();
110-
encoder.clear();
127+
char fileName[15];
128+
sprintf(fileName, "%10lu.cdu", currentDrive->startTime);
129+
130+
int fileid = logger.begin(fileName);
111131

112-
logger.dispatch(res.c_str(), res.length());
132+
int8_t *buffer;
133+
size_t bufferSize;
134+
//TODO: Get actual fuel level
135+
currentDrive->getDriveData(&buffer, &bufferSize, 50);
136+
137+
Serial.print("Final Buffer size: ");
138+
Serial.print(bufferSize);
139+
Serial.println();
140+
141+
logger.dispatch((const char *)buffer, bufferSize);
113142
logger.flush();
114143
logger.end();
144+
145+
free(buffer);
146+
115147
hasConnected = false;
116148
hasSaved = true;
149+
150+
currentDrive = NULL;
117151
}
118152

119153
}

0 commit comments

Comments
 (0)