Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ Serial interface to transmit telemetry data to Jeti Duplex receivers. For Arduin
in order to improve behaviour on telemetry reset
1.04 07/18/2017 dynamic sensor de-/activation
1.05 11/12/2017 send 3 textframes before start of EX transmission to get transmitter ready
1.06 02/14/2021 enhance interface / implementation for priorized sensor send capabilities (SetSensorValue(id, value, prio))
to avoid deffered transmission of high prio data (vario).
1.07 02/18/2021 fixed priorized sensor implementation and added interface to speed up frame send cycle (SetJetiSendCycle(aTime))
1.08 02/28/2021 - bug fix: ex buffer overrun for sensor ids >15 fixed (forced strange behaviour in prio handling)
- some more index size checks
- simplified code for prio data handling
- handling of -1 as invalid data removed, due to dynamic prio (SetSensorValue(..., prio) and SetSensorActive()
interface


== License ==

Expand Down
6 changes: 3 additions & 3 deletions library.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name=JetiExSensor
version=1.0.5
author=Bernd Wokoeck
version=1.1.0
author=Bernd Wokoeck/Rainer Stransky
maintainer=
sentence=Serial interface to transmit telemetry data to Jeti Duplex receivers. For Arduino Mini Pro 328, Nano, Leonardo/Pro Micro and Teensy 3.x
paragraph=Connect your Arduino mini to a Jeti duplex receiver and see telemetry values on your transmitter display.
category=Communication
url=https://sourceforge.net/projects/jetiexsensorcpplib/JetiExSensor_V1.0.5.zip
url=
architectures=avr
128 changes: 87 additions & 41 deletions src/JetiExProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@
in order to improve behaviour on telemetry reset
1.04 07/18/2017 dynamic sensor de-/activation
1.05 11/12/2017 send 3 textframes before start of EX transmission to get transmitter ready
1.06 02/14/2021 Rainer Stransky: added implementation for priorized sensor send capabilities (SetSensorValue(id, value, prio))
to avoid deffered transmission of high prio data (vario).
1.07 02/18/2021 Rainer Stransky: fixed priorized sensor implementation and added interface to speed up frame send cycle
SetJetiSendCycle(aTime);
1.08 02/28/2021 - bug fix: ex buffer overrun for sensor ids >15 fixed (forced strange behaviour in prio handling)
- some more index size checks
- simplified code for prio data handling
- handling of -1 as invalid data removed, due to dynamic prio (SetSensorValue(..., prio) and SetSensorActive()
interface

Todo:
- better check for ex buffer overruns
Expand Down Expand Up @@ -83,6 +92,7 @@ JetiSensor::JetiSensor( int arrIdx, JetiExProtocol * pProtocol )

// value
m_value = pProtocol->m_pValues[ arrIdx ].m_value;
m_prio = pProtocol->m_pValues[ arrIdx ].m_prio;

// copy to combined sensor/value buffer
copyLabel( (const uint8_t*)constData.text, (const uint8_t*)constData.unit, m_label, sizeof( m_label ), &m_textLen, &m_unitLen );
Expand Down Expand Up @@ -111,7 +121,7 @@ JetiSensor::JetiSensor( int arrIdx, JetiExProtocol * pProtocol )
JetiExProtocol::JetiExProtocol() :
m_tiLastSend( 0 ), m_frameCnt( 0 ), m_nameLen( 0 ), m_pSensorsConst( 0 ), m_pValues( 0 ), m_nSensors( 0 ),
m_sensorIdx( 0 ), m_dictIdx( 0 ), m_pSerial( 0 ), m_alarmChar( 0 ), m_bExitNav( 0 ),
m_devIdLow( DEVICE_ID_LOW ), m_devIdHi( DEVICE_ID_HI )
m_devIdLow( DEVICE_ID_LOW ), m_devIdHi( DEVICE_ID_HI ), m_ExFrameSendCycle ( 150 ) , m_ValueCycleCnt ( 1 )
{
m_name[0] = '\0';
memset( m_activeSensors, 255, sizeof(m_activeSensors) ); // default: all sensors active
Expand Down Expand Up @@ -173,10 +183,15 @@ uint8_t JetiExProtocol::GetJetiboxKey()
return m_pSerial->Getchar();
}

/// set the send cycle to the given value in ms (min = 75)
void JetiExProtocol::SetJetiSendCycle(uint8_t aTime) {
m_ExFrameSendCycle = max (75, aTime);
}

uint8_t JetiExProtocol::DoJetiSend()
{
// send every 150 ms only
if( ( m_tiLastSend + 150 ) <= millis() )
if( ( m_tiLastSend + m_ExFrameSendCycle ) <= millis() )
{
m_tiLastSend = millis();

Expand Down Expand Up @@ -205,13 +220,28 @@ uint8_t JetiExProtocol::DoJetiSend()
return 0;
}

void JetiExProtocol::SetSensorValue( uint8_t id, int32_t value )
/**
* @id: id of the sensor
* @value: value of the sensor to be transferred
* @prio: transmission prioity: 1=send with every frame, 2=send with every second frame, ....,
* #defines avaiable
* JEP_PRIO_ULTRA_HIGH 1
* JEP_PRIO_HIGH 3
* JEP_PRIO_STANDARD 5
* JEP_PRIO_LOW 10
* JEP_PRIO_ULTRA_LOW 15
*/
void JetiExProtocol::SetSensorValue( uint8_t id, int32_t value , uint8_t prio)
{
if( m_pValues && id < sizeof( m_sensorMapper ) )
m_pValues[ m_sensorMapper[ id ] ].m_value = value;
if( m_pValues && id < sizeof( m_sensorMapper ) ) {
if (m_sensorMapper[ id ] < m_nSensors) {
m_pValues[ m_sensorMapper[ id ] ].m_value = value;
m_pValues[ m_sensorMapper[ id ] ].m_prio = prio;
}
}
}

void JetiExProtocol::SetSensorValueGPS( uint8_t id, bool bLongitude, float value )
void JetiExProtocol::SetSensorValueGPS( uint8_t id, bool bLongitude, float value, uint8_t prio )
{
// Jeti doc: If the lowest bit of a decimal point (Bit 5) equals log. 1, the data represents longitude. According to the highest bit (30) of a decimal point it is either West (1) or East (0).
// Jeti doc: If the lowest bit of a decimal point (Bit 5) equals log. 0, the data represents latitude. According to the highest bit (30) of a decimal point it is either South (1) or North (0).
Expand All @@ -236,10 +266,10 @@ void JetiExProtocol::SetSensorValueGPS( uint8_t id, bool bLongitude, float value
gps.vBytes[3] |= bLongitude ? 0x20 : 0;
gps.vBytes[3] |= (value < 0) ? 0x40 : 0;

SetSensorValue( id, gps.vInt );
SetSensorValue( id, gps.vInt, prio );
}

void JetiExProtocol::SetSensorValueDate( uint8_t id, uint8_t day, uint8_t month, uint16_t year )
void JetiExProtocol::SetSensorValueDate( uint8_t id, uint8_t day, uint8_t month, uint16_t year, uint8_t prio )
{
// Jeti doc: If the lowest bit of a decimal point equals log. 1, the data represents date
// Jeti doc: (decimal representation: b0-7 day, b8-15 month, b16-20 year - 2 decimals, number 2000 to be added).
Expand All @@ -259,10 +289,10 @@ void JetiExProtocol::SetSensorValueDate( uint8_t id, uint8_t day, uint8_t month,
date.vBytes[2] = day & 0x1F;
date.vBytes[2] |= 0x20;

SetSensorValue( id, date.vInt );
SetSensorValue( id, date.vInt, prio );
}

void JetiExProtocol::SetSensorValueTime( uint8_t id, uint8_t hour, uint8_t minute, uint8_t second )
void JetiExProtocol::SetSensorValueTime( uint8_t id, uint8_t hour, uint8_t minute, uint8_t second, uint8_t prio )
{
// If the lowest bit of a decimal point equals log. 0, the data represents time
// (decimal representation: b0-7 seconds, b8-15 minutes, b16-20 hours).
Expand All @@ -277,21 +307,22 @@ void JetiExProtocol::SetSensorValueTime( uint8_t id, uint8_t hour, uint8_t minut
date.vBytes[1] = minute;
date.vBytes[2] = hour & 0x1F;

SetSensorValue( id, date.vInt );
SetSensorValue( id, date.vInt, prio );
}

void JetiExProtocol::SetSensorActive( uint8_t id, bool bEnable, JETISENSOR_CONST * pSensorArray )
{
if( m_nSensors == 0 && pSensorArray ) // dont do it more than once
InitSensorMapper( pSensorArray );

if( id < sizeof( m_sensorMapper ) )
{
if( id < sizeof( m_sensorMapper ) ) {
int idx = m_sensorMapper[ id ];
if( bEnable )
m_activeSensors[ idx >>3 ] |= 1 << (idx & 7);
else
m_activeSensors[ idx >>3 ] &= ~(1 << (idx & 7));
if (idx < m_nSensors) {
if( bEnable )
m_activeSensors[ idx >>3 ] |= 1 << (idx & 7);
else
m_activeSensors[ idx >>3 ] &= ~(1 << (idx & 7));
}
}

// restart sending dictionary
Expand Down Expand Up @@ -396,7 +427,7 @@ void JetiExProtocol::SendExFrame( uint8_t frameCnt )
// sensor name in frame 0
if( frameCnt == 0 )
{ // sensor name
m_exBuffer[2] = 0x00; // 2Bit packet type(0-3) 0x40=Data, 0x00=Text
m_exBuffer[2] = 0x00; // 2Bit packet type(0-3) 0x40=Data, 0x00=Text
m_exBuffer[8] = 0x00; // 8Bit id
m_exBuffer[9] = m_nameLen<<3; // 5Bit description, 3Bit unit length (use one space character)
memcpy( m_exBuffer + 10, m_name, m_nameLen ); // copy label plus unit to ex buffer starting from pos 10
Expand All @@ -414,8 +445,8 @@ void JetiExProtocol::SendExFrame( uint8_t frameCnt )
if( sensor.m_bActive )
{
m_exBuffer[2] = 0x00; // 2Bit packet type(0-3) 0x40=Data, 0x00=Text
m_exBuffer[8] = sensor.m_id; // 8Bit id
m_exBuffer[9] = (sensor.m_textLen<<3) | sensor.m_unitLen; // 5Bit description, 3Bit unit length
m_exBuffer[8] = sensor.m_id; // 8Bit id
m_exBuffer[9] = (sensor.m_textLen<<3) | sensor.m_unitLen; // 5Bit description, 3Bit unit length
n = sensor.jetiCopyLabel( m_exBuffer, 10 ) + 10; // copy label plus unit to ex buffer starting from pos 10
break;
}
Expand All @@ -426,43 +457,57 @@ void JetiExProtocol::SendExFrame( uint8_t frameCnt )
{
int bufLen;
int nVal = 0; // count values
m_exBuffer[ 2 ] = 0x40; // 2Bit Type(0-3) 0x40=Data, 0x00=Text
n=8; // start at nineth byte in buffer
m_exBuffer[ 2 ] = 0x40; // 2Bit Type(0-3) 0x40=Data, 0x00=Text
n=8; // start at nineth byte in buffer

do
{
bufLen = 0; // last value buffer length
JetiSensor sensor( m_sensorIdx, this );
if( ++m_sensorIdx >= m_nSensors ) // wrap index when array is at the end
m_sensorIdx = 0;

if( sensor.m_bActive && sensor.m_value != -1 ) // -1 is "invalid"
{
if( sensor.m_id > 15 )
{
m_exBuffer[n++] = 0x0 | (sensor.m_dataType & 0x0F); // sensor id > 15 --> put id to next byte
m_exBuffer[n++] = sensor.m_id;
}
else
m_exBuffer[n++] = (sensor.m_id<<4) | (sensor.m_dataType & 0x0F); // 4Bit id, 4 bit data type (i.e. int14_t)

bufLen = sensor.m_bufLen;
if( sensor.m_bActive && ((m_ValueCycleCnt%sensor.m_prio) == 0)) {
// id+type+value+precision + CRC
bufLen = sensor.m_bufLen + 1 ;
if( sensor.m_id > 15 ) {
// next byte for id > 15
bufLen++;
if (n + bufLen > JEP_MAX_BYTE_PER_BUF) {
// not enough bytes free
break;
}
m_exBuffer[n++] = 0x0 | (sensor.m_dataType & 0x0F); // sensor id > 15 --> put id to next byte
m_exBuffer[n++] = sensor.m_id;
} else {
if (n + bufLen > JEP_MAX_BYTE_PER_BUF) {
// not enough bytes free
break;
}
m_exBuffer[n++] = (sensor.m_id<<4) | (sensor.m_dataType & 0x0F); // 4Bit id, 4 bit data type (i.e. int14_t)
}

n += sensor.jetiEncodeValue( m_exBuffer, n );
}
if( ++nVal >= m_nSensors ) // dont send twice in a frame

if( ++m_sensorIdx >= m_nSensors ) { // wrap index when array is at the end
m_sensorIdx = 0;
m_ValueCycleCnt++;
}
if( ++nVal >= m_nSensors ) { // dont send twice in a frame
break;
}
}
while( n < ( 26 - bufLen ) ); // jeti spec says max 29 Bytes per buffer
while( true ); // jeti spec says max 29 Bytes per buffer
}

// complete some more EX frame data
m_exBuffer[0] = 0x7E; m_exBuffer[1] = 0x2F; // EX-Frame Separator
m_exBuffer[2] |= n-2; // frame length to Byte 2
// 8 Byte Header
m_exBuffer[0] = 0x7E; m_exBuffer[1] = 0x2F; // EX-Frame Separator
m_exBuffer[2] |= n-2; // frame length to Byte 2
m_exBuffer[3] = MANUFACTURER_ID_LOW; m_exBuffer[4] = MANUFACTURER_ID_HI; // sensor ID
m_exBuffer[5] = m_devIdLow; m_exBuffer[6] = m_devIdHi;
m_exBuffer[7] = 0x00; // reserved (key for encryption)

// calculate crc
// 1 Byte CRC
m_exBuffer[n] = jeti_crc8( m_exBuffer, n );

// serial transmission
Expand Down Expand Up @@ -502,7 +547,7 @@ uint8_t JetiSensor::jetiEncodeValue( uint8_t * exbuf, uint8_t n )
exbuf[n] = ( m_value & 0x1F) | ((m_value < 0) ? 0x80 :0x00 ); // 5 bit value and sign
exbuf[n] |= m_precision; // precision in bit 5/6 (0, 20, 40)
return 1;
case TYPE_14b:
exbuf[n] = m_value & 0xFF; // lo byte
exbuf[n + 1] = ( (m_value >> 8) & 0x1F) | ((m_value < 0) ? 0x80 :0x00 ); // 5 bit hi byte and sign
Expand Down Expand Up @@ -579,3 +624,4 @@ uint8_t JetiExProtocol::jeti_crc8 (uint8_t *exbuf, unsigned char framelen)
crc = update_crc (exbuf[c], crc);
return (crc);
}

36 changes: 31 additions & 5 deletions src/JetiExProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@
- JETI_DEBUG and BLOCKING_MODE removed (cleanup)
1.02 03/28/2017 New sensor memory management. Sensor data can be located in PROGMEM
1.04 07/18/2017 dynamic sensor de-/activation
1.05 02/14/2021 Rainer Stransky: added implementation for priorized sensor send capabilities (SetSensorValue(id, value, prio))
to avoid deffered transmission of high prio data (vario).
1.07 02/18/2021 Rainer Stransky: fixed priorized sensor implementation and added interface to speed up frame send cycle
SetJetiSendCycle(aTime);
1.08 02/28/2021 - bug fix: ex buffer overrun for sensor ids >15 fixed (forced strange behaviour in prio handling)
- some more index size checks
- simplified code for prio data handling
- handling of -1 as invalid data removed, due to dynamic prio (SetSensorValue(..., prio) and SetSensorActive()
interface

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
Expand All @@ -47,12 +56,20 @@
#ifndef JETIEXPROTOCOL_H
#define JETIEXPROTOCOL_H

#define JEP_PRIO_ULTRA_HIGH 1
#define JEP_PRIO_HIGH 3
#define JEP_PRIO_STANDARD 5
#define JEP_PRIO_LOW 10
#define JEP_PRIO_ULTRA_LOW 15

#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

#define JEP_MAX_BYTE_PER_BUF 29

#include "JetiExSerial.h"
#include <new.h>

Expand Down Expand Up @@ -80,11 +97,14 @@ class JetiValue
friend class JetiExProtocol;
public:

JetiValue() : m_value( -1 ) {}
JetiValue() : m_value( -1 ), m_prio( 0 ) {}

protected:
// value
int32_t m_value;

// send priority
uint8_t m_prio;
};

// complete data for a sensor to fill ex frame buffer
Expand Down Expand Up @@ -116,6 +136,9 @@ class JetiSensor
// value
uint8_t m_bActive;

// send priority / incidence
uint8_t m_prio;

// label/description of value
uint8_t m_label[ 20 ];
uint8_t m_textLen;
Expand Down Expand Up @@ -164,12 +187,13 @@ class JetiExProtocol

void Start( const char * name, JETISENSOR_CONST * pSensorArray, enComPort comPort = DEFAULTPORT ); // call once in setup(), comPort: 0=Default, Teensy: 1..3
uint8_t DoJetiSend(); // call periodically in loop()
void SetJetiSendCycle(uint8_t aTime);

void SetDeviceId( uint8_t idLo, uint8_t idHi ) { m_devIdLow = idLo; m_devIdHi = idHi; } // adapt it, when you have multiple sensor devices connected to your REX
void SetSensorValue( uint8_t id, int32_t value );
void SetSensorValueGPS( uint8_t id, bool bLongitude, float value );
void SetSensorValueDate( uint8_t id, uint8_t day, uint8_t month, uint16_t year );
void SetSensorValueTime( uint8_t id, uint8_t hour, uint8_t minute, uint8_t second );
void SetSensorValue( uint8_t id, int32_t value, uint8_t prio=1 );
void SetSensorValueGPS( uint8_t id, bool bLongitude, float value, uint8_t prio=1 );
void SetSensorValueDate( uint8_t id, uint8_t day, uint8_t month, uint16_t year , uint8_t prio=1 );
void SetSensorValueTime( uint8_t id, uint8_t hour, uint8_t minute, uint8_t second , uint8_t prio=1 );
void SetSensorActive( uint8_t id, bool bEnable, JETISENSOR_CONST * pSensorArray );
void SetJetiboxText( enLineNo lineNo, const char* text );
void SetJetiboxExit() { m_bExitNav = true; };
Expand All @@ -195,6 +219,7 @@ class JetiExProtocol
// EX frame control
unsigned long m_tiLastSend; // last send time
uint8_t m_frameCnt;
uint8_t m_ExFrameSendCycle;

// sensor name
char m_name[ 20 ];
Expand All @@ -205,6 +230,7 @@ class JetiExProtocol
JetiValue * m_pValues; // sensor value array, same order as constant data array
int m_nSensors; // number of sensors
uint8_t m_sensorIdx; // current index to sensor array to send value
uint8_t m_ValueCycleCnt; // current index to sensor array to send value
uint8_t m_dictIdx; // current index to sensor array to send sensor dictionary
uint8_t m_sensorMapper[ MAX_SENSORS ]; // id to idx lookup table to accelerate SetSensorValue()
uint8_t m_activeSensors[ MAX_SENSORBYTES ]; // bit array for active sensor bit field
Expand Down