Skip to content

Commit

Permalink
Implement binary mode data output, update basic example, update libra…
Browse files Browse the repository at this point in the history
…ry info
  • Loading branch information
chrisdalke committed Jan 21, 2021
1 parent f18a9e5 commit d7d7c07
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 106 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
11 changes: 2 additions & 9 deletions examples/BasicOutput/BasicOutput.ino
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ data from your hardware. Code not required.
Distributed "as is" under the MIT License. See LICENSE.md for details.
*/

// EXAMPLE 1: Basic Output
// This example configures the SDK and sends randomly generated data points.
// You'll learn how to:
// 1) Initialize the SDK
// 2) Create data dimensions
// 3) Write values

#include <TelemetryJet.h>

// Initialize an instance of the TelemetryJet SDK.
Expand Down Expand Up @@ -50,9 +43,9 @@ void loop() {
// time to process serial data as it is received.
telemetry.update();

// Update the dimension with an oscillating signal.
// Update the dimensions with an oscillating signal.
// Note that although this loop is running as fast as possible,
// TelemetryJet will only send data at the interval specified earlier.
testValue1.setInt32(sin(millis() / 1000.0) * 100.0);
testValue1.setFloat32(sin(millis() / 1000.0) * 100.0);
testValue2.setFloat32(sin(millis() / 2000.0) * 200.0);
}
6 changes: 3 additions & 3 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=TelemetryJet
version=0.1.1
version=0.1.2
author=Chris Dalke <chrisdalke@gmail.com>
maintainer=Chris Dalke <chrisdalke@gmail.com>
sentence=Lightweight communication library for hardware telemetry data.
paragraph=Handles bidirectional communication and state management for data points. Part of the TelemetryJet platform.
sentence=A lightweight telemetry protocol for hardware sensor data.
paragraph=Provides a high-level API for sending and receiving data points over a serial connection. Uses an efficient MessagePack-based protocol with packet framing, error detection, and more. Part of the TelemetryJet platform.
category=Communication
url=https://github.com/telemetryjet/telemetryjet-arduino-sdk
architectures=*
208 changes: 116 additions & 92 deletions src/TelemetryJet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,92 +104,74 @@ void TelemetryJet::update() {
}

if (millis() - lastSent >= transmitRate && numDimensions > 0) {
bool wroteValue = false;
bool hasValue = !isDeltaMode;
for (uint16_t i = 0; i < numDimensions; i++) {
if (dimensions[i]->hasValue && (dimensions[i]->hasNewValue || !isDeltaMode)) {
dimensions[i]->hasNewValue = false;
switch (dimensions[i]->type) {
case DataPointType::BOOLEAN: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((unsigned int)(dimensions[i]->value.v_bool));
transport->write('\n');
break;
}
case DataPointType::UINT8: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((unsigned int)(dimensions[i]->value.v_uint8));
transport->write('\n');
break;
}
case DataPointType::UINT16: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((unsigned int)(dimensions[i]->value.v_uint16));
transport->write('\n');
break;
}
case DataPointType::UINT32: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((unsigned long)(dimensions[i]->value.v_uint32));
transport->write('\n');
break;
}
case DataPointType::UINT64: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((unsigned long)(dimensions[i]->value.v_uint64));
transport->write('\n');
break;
}
case DataPointType::INT8: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((int)(dimensions[i]->value.v_int8));
transport->write('\n');
break;
}
case DataPointType::INT16: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((int)(dimensions[i]->value.v_int16));
transport->write('\n');
break;
}
case DataPointType::INT32: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((long)(dimensions[i]->value.v_int32));
transport->write('\n');
break;
}
case DataPointType::INT64: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((long)(dimensions[i]->value.v_int64));
transport->write('\n');
break;
}
case DataPointType::FLOAT32: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((double)(dimensions[i]->value.v_float32));
transport->write('\n');
break;
}
case DataPointType::FLOAT64: {
transport->print((unsigned int)dimensions[i]->key);
transport->print('=');
transport->print((double)(dimensions[i]->value.v_float64));
transport->write('\n');
break;
}
default: {
break;
if (dimensions[i]->hasNewValue) {
hasValue = true;
}
}
if (hasValue) {
for (uint16_t i = 0; i < numDimensions; i++) {
if (dimensions[i]->hasNewValue) {
dimensions[i]->hasNewValue = false;
}
if (dimensions[i]->hasValue) {
switch (dimensions[i]->type) {
case DataPointType::BOOLEAN: {
transport->print((unsigned int)(dimensions[i]->value.v_bool));
break;
}
case DataPointType::UINT8: {
transport->print((unsigned int)(dimensions[i]->value.v_uint8));
break;
}
case DataPointType::UINT16: {
transport->print((unsigned int)(dimensions[i]->value.v_uint16));
break;
}
case DataPointType::UINT32: {
transport->print((unsigned long)(dimensions[i]->value.v_uint32));
break;
}
case DataPointType::UINT64: {
transport->print((unsigned long)(dimensions[i]->value.v_uint64));
break;
}
case DataPointType::INT8: {
transport->print((int)(dimensions[i]->value.v_int8));
break;
}
case DataPointType::INT16: {
transport->print((int)(dimensions[i]->value.v_int16));
break;
}
case DataPointType::INT32: {
transport->print((long)(dimensions[i]->value.v_int32));
break;
}
case DataPointType::INT64: {
transport->print((long)(dimensions[i]->value.v_int64));
break;
}
case DataPointType::FLOAT32: {
transport->print((double)(dimensions[i]->value.v_float32));
break;
}
case DataPointType::FLOAT64: {
transport->print((double)(dimensions[i]->value.v_float64));
break;
}
default: {
break;
}
}
} else {
transport->write('0');
}
transport->write(' ');
}
transport->write('\n');
}
lastSent = millis();
}
Expand All @@ -198,14 +180,60 @@ void TelemetryJet::update() {
// Full-featured input and output
while (transport->available() > 0) {
uint8_t inByte = transport->read();
/*
if (rxIndex >= 32) {
rxIndex = 0;
}
rxBuffer[rxIndex++] = inByte;
// 0x0 pads the end of a packet
if (inByte == 0x0) {
if (rxIndex > 5) {
// If we see 0x0 and have contents in the buffer, read packet
// Minimum length of a packet is 5 bytes:
// - Checksum (1 byte)
// - Checksum correction byte (1 byte)
// - Key (1+ byte)
// - Type (1+ byte)
// - Value (1+ byte)
// - Packet boundary (0x0, 1 byte)
// 1 - Validate checksum
uint8_t checksum = 0;
for (uint16_t bufferIdx = 0; bufferIdx < rxIndex; bufferIdx++) {
checksum += (uint8_t)rxBuffer[bufferIdx];
}
if (checksum == 0xFF) {
// Expand COBS encoded binary string
size_t packetLength = UnStuffData(rxBuffer, rxIndex, tempBuffer);
// Process messagepack structure
mpack_reader_t reader;
mpack_reader_init_data(&reader, tempBuffer, packetLength);
mpack_tag_t key = mpack_read_tag(&reader);
mpack_tag_t type = mpack_read_tag(&reader);
mpack_tag_t value = mpack_read_tag(&reader);
mpack_read_u8
if (mpack_reader_destroy(&reader) == mpack_ok) {
// Write packet
}
} else {
numDroppedRxPackets++;
}
}
rxIndex = 0;
}
*/
}
if (millis() - lastSent >= transmitRate && numDimensions > 0) {
mpack_writer_t writer;
size_t packetLength;
for (uint16_t i = 0; i < numDimensions; i++) {
if (dimensions[i]->hasValue && (dimensions[i]->hasNewValue || !isDeltaMode)) {
dimensions[i]->hasNewValue = false;
mpack_writer_init(&writer, messagePackBuffer, 32);
mpack_writer_init(&writer, tempBuffer, 32);

// Write key and type headers
mpack_write_u16(&writer, (uint16_t)dimensions[i]->key);
Expand Down Expand Up @@ -266,7 +294,7 @@ void TelemetryJet::update() {
// https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
// to replace all 0x0 bytes in the packet.
// This way, we can use 0x0 as a packet frame marker.
packetLength = StuffData(messagePackBuffer, packetLength, txBuffer);
packetLength = StuffData(tempBuffer, packetLength, txBuffer);

// Compute checksum and add to front of the packet
// We never want the checksum to == 0,
Expand All @@ -287,18 +315,14 @@ void TelemetryJet::update() {
}

// Write checksum and checksum correction byte
transport->print((uint8_t)checksum);
transport->print(' ');
transport->print((uint8_t)checksumCorrectionByte);
transport->print(' ');
transport->write((uint8_t)checksum);
transport->write((uint8_t)checksumCorrectionByte);

// Write buffer
for (uint16_t bufferIdx = 0; bufferIdx < packetLength; bufferIdx++) {
transport->print((uint8_t)txBuffer[bufferIdx]);
transport->print(' ');
transport->write((uint8_t)txBuffer[bufferIdx]);
}
transport->print((uint8_t)0x0);
transport->println();
numTxPackets++;
}
}
lastSent = millis();
Expand Down
7 changes: 5 additions & 2 deletions src/TelemetryJet.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,15 @@ class TelemetryJet {
uint16_t numDimensions = 0;
uint16_t dimensionCacheLength = 8;

// Allocate fixed input, output, and encoding/decoding buffers
char messagePackBuffer[32];
// Allocate fixed input, output, and temporary buffers
char tempBuffer[32];
char rxBuffer[32];
char txBuffer[32];
uint8_t rxIndex;
uint8_t txIndex;
uint32_t numDroppedRxPackets;
uint32_t numRxPackets;
uint32_t numTxPackets;
public:
TelemetryJet(Stream *transport, unsigned long transmitRate);

Expand Down

0 comments on commit d7d7c07

Please sign in to comment.