From bf8c3c88bc0ed8304723c7afe406b54ce3f24734 Mon Sep 17 00:00:00 2001 From: Thomas Miric Date: Thu, 21 Jan 2016 18:22:39 +0100 Subject: [PATCH 1/5] Add Jeti Ex Bus receiver with telemetry capabilities --- Makefile | 1 + src/main/io/serial_cli.c | 3 +- src/main/rx/jetiexbus.c | 591 +++++++++++++++++++++++++++++++++ src/main/rx/jetiexbus.h | 35 ++ src/main/rx/rx.c | 7 + src/main/rx/rx.h | 3 +- src/main/telemetry/telemetry.c | 6 +- 7 files changed, 643 insertions(+), 3 deletions(-) create mode 100644 src/main/rx/jetiexbus.c create mode 100644 src/main/rx/jetiexbus.h diff --git a/Makefile b/Makefile index d4849c9818..4e5f715038 100644 --- a/Makefile +++ b/Makefile @@ -315,6 +315,7 @@ COMMON_SRC = build_config.c \ rx/spektrum.c \ rx/xbus.c \ rx/ibus.c \ + rx/jetiexbus.c \ sensors/acceleration.c \ sensors/battery.c \ sensors/boardalignment.c \ diff --git a/src/main/io/serial_cli.c b/src/main/io/serial_cli.c index cf901b93bf..2b28933615 100644 --- a/src/main/io/serial_cli.c +++ b/src/main/io/serial_cli.c @@ -361,7 +361,8 @@ static const char * const lookupTableSerialRX[] = { "SUMH", "XB-B", "XB-B-RJ01", - "IBUS" + "IBUS", + "JETIEXBUS" }; static const char * const lookupTableGyroLpf[] = { diff --git a/src/main/rx/jetiexbus.c b/src/main/rx/jetiexbus.c new file mode 100644 index 0000000000..cdb6506103 --- /dev/null +++ b/src/main/rx/jetiexbus.c @@ -0,0 +1,591 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + * + * Authors: + * Thomas Miric - marv-t + * + * Jeti EX Bus Communication Protocol: + * http://www.jetimodel.com/en/show-file/642/ + * + * JETI Telemetry Communication Protocol: + * http://www.jetimodel.com/en/show-file/26/ + * + * Following restrictions: + * Communication speed: 125000 bps + * Number of channels: 16 + * + * Connect as follows: + * Jeti EX Bus -> Serial RX (connect directly) + * Serial TX -> Resistor(2k4) ->Serial RX + * In jeti pdf it is different, but if the resistor breaks, the receiver continues to operate. + * + */ + +#include +#include + +#include "platform.h" +#include "build_config.h" +#include "drivers/system.h" +#include "drivers/serial.h" +#include "drivers/serial_uart.h" +#include "io/serial.h" +#include "rx/jetiexbus.h" + + +#ifdef TELEMETRY + +#include +#include "sensors/sensors.h" +#include "sensors/battery.h" +#include "sensors/barometer.h" +#include "telemetry/telemetry.h" + +#endif //TELEMETRY + +#include "rx/rx.h" + +// +// Serial driver for Jeti EX Bus receiver +// +#define JETIEXBUS_BAUDRATE 125000 // EX Bus 125000; EX Bus HS 250000 not supported +#define JETIEXBUS_OPTIONS (SERIAL_STOPBITS_1 | SERIAL_PARITY_NO | SERIAL_NOT_INVERTED ) + +#define JETIEXBUS_MIN_FRAME_GAP 1 + +#define JETIEXBUS_CHANNEL_COUNT 16 // most Jeti TX transmit 16 channels +#define JETIEXBUS_MIN_FRAME_SIZE 8 +#define JETIEXBUS_HEADER_LEN 6 +#define JETIEXBUS_CRC_LEN 2 + +#define JETIEXBUS_MAX_FRAME_SIZE (JETIEXBUS_HEADER_LEN + JETIEXBUS_CHANNEL_COUNT*2 + JETIEXBUS_CRC_LEN) +#define JETIEXBUS_FRAME_OFFSET (JETIEXBUS_MAX_FRAME_SIZE) +#define JETIEXBUS_MAX_REQUESTFRAME_SIZE 8 + +#define JETIEXBUS_START_CHANNEL_FRAME (0x3E) +#define JETIEXBUS_START_REQUEST_FRAME (0x3D) + +#define EXBUS_CHANNELDATA (0x3E03) // Frame contains channeldata +#define EXBUS_CHANNELDATA_TELEMETRY_REQUEST (0x3E01) // Frame contains channeldata, but with a request for data + + +enum { + EXBUS_STATE_ZERO = 0, + EXBUS_STATE_IN_PROGRESS, + EXBUS_STATE_RECEIVED, + EXBUS_STATE_PROCESSED +}; + +enum { + EXBUS_TRANS_ZERO = 0, + EXBUS_TRANS_RX_READY, + EXBUS_TRANS_RX, + EXBUS_TRANS_TX_READY, + EXBUS_TRANS_TX +}; + +enum exBusHeader_e { + EXBUS_HEADER_SYNC = 0, + EXBUS_HEADER_REQ, + EXBUS_HEADER_MSG_LEN, + EXBUS_HEADER_PACKET_ID, + EXBUS_HEADER_DATA_ID, + EXBUS_HEADER_SUBLEN, + EXBUS_HEADER_DATA +}; + +#ifdef TELEMETRY + +enum exTelHeader_e { + EXTEL_HEADER_SYNC = 0, + EXTEL_HEADER_TYPE_LEN, + EXTEL_HEADER_USN_LB, + EXTEL_HEADER_USN_HB, + EXTEL_HEADER_LSN_LB, + EXTEL_HEADER_LSN_HB, + EXTEL_HEADER_RES, + EXTEL_HEADER_ID, + EXTEL_HEADER_DATA +}; + + +enum exDataType_e { + EX_TYPE_6b = 0, // int6_t Data type 6b (-31 ¸31) + EX_TYPE_14b = 1, // int14_t Data type 14b (-8191 ¸8191) + EX_TYPE_22b = 4, // int22_t Data type 22b (-2097151 ¸2097151) + EX_TYPE_DT = 5, // int22_t Special data type – time and date + EX_TYPE_30b = 8, // int30_t Data type 30b (-536870911 ¸536870911) + EX_TYPE_GPS = 9 // int30_t Special data type – GPS coordinates: lo/hi minute - lo/hi degree. +}; + +typedef struct exBusSensor_s{ + const char *name; + const char *unit; + int32_t value; + const uint8_t exDataType; + const uint32_t decimals; +} exBusSensor_t; + + +#define SETMASK(decimals, bytes) (decimals<<((bytes*8)-3)) +#define RESETMASK(bytes) (~(3 << ((bytes*8)-3))) + +const uint32_t resetMask[]={ RESETMASK(1), RESETMASK(2), RESETMASK(3), RESETMASK(4) }; + +// list of telemetry messages +// after 15 sensors must be a new Header : "CF-Dev 1.12 S2" + +exBusSensor_t jetiExSensors[] = { + { "CF-Dev 1.12 S1", "", 0, 0, 0 }, + { "Voltage", "V", 0, EX_TYPE_14b, SETMASK(1,2) }, + { "Current", "A", 0, EX_TYPE_14b, SETMASK(2,2) }, + { "Altitude", "m", 0, EX_TYPE_14b, SETMASK(1,2) }, + { "Capacity", "mAh", 0, EX_TYPE_14b, SETMASK(0,2) } +}; + +// after 15 sensors a new enum value to be set: EX_NEW_SENSOR = 17 +enum exSensors_e { + EX_VOLTAGE = 1, + EX_CURRENT, + EX_ALTITUDE, + EX_CAPACITY +}; + +#define JETI_EX_SENSOR_COUNT (sizeof(jetiExSensors) / sizeof(exBusSensor_t)) + +#endif //TELEMETRY + +static serialPort_t *jetiExBusPort; +static serialPortConfig_t *portConfig; + +static uint8_t jetiExBusFrameState = EXBUS_STATE_ZERO; +static uint8_t jetiExBusRequestState = EXBUS_STATE_ZERO; +static uint8_t jetiExBusFramePosition; +static uint8_t jetiExBusFrameLength; + +// Use max values for ram areas +static uint8_t jetiExBusSerialFrame[JETIEXBUS_MAX_FRAME_SIZE+JETIEXBUS_MAX_REQUESTFRAME_SIZE]; +static uint8_t *jetiExBusFrame; + + +static uint16_t jetiExBusChannelData[JETIEXBUS_CHANNEL_COUNT]; +static void jetiExBusDataReceive(uint16_t c); +static uint16_t jetiExBusReadRawRC(rxRuntimeConfig_t *rxRuntimeConfig, uint8_t chan); + + +#ifdef TELEMETRY + +static uint8_t jetiExBusTelemetryFrame[JETIEXBUS_MAX_FRAME_SIZE]; +static uint8_t jetiExBusTransceiveState = EXBUS_TRANS_RX; +static uint8_t *jetiExTelemetry=&jetiExBusTelemetryFrame[EXBUS_HEADER_DATA]; +static void sendJetiExBusTelemetry(uint8_t packetID); + +uint8_t updateCRC8( uint8_t crc, uint8_t data ); +uint8_t calcCRC8(uint8_t *pt, uint8_t msgLen); + +#endif //TELEMETRY + +uint16_t updateCRC16( uint16_t crc, uint8_t data ); +uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen); + + + + +bool jetiExBusInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback) +{ + UNUSED(rxConfig); + + if (callback) { + *callback = jetiExBusReadRawRC; + } + + rxRuntimeConfig->channelCount = JETIEXBUS_CHANNEL_COUNT; + jetiExBusFramePosition = 0; + jetiExBusFrameLength = JETIEXBUS_MAX_FRAME_SIZE; + + portConfig = findSerialPortConfig(FUNCTION_RX_SERIAL); + + if (!portConfig) { + return false; + } + + jetiExBusPort = openSerialPort(portConfig->identifier, FUNCTION_RX_SERIAL, jetiExBusDataReceive, JETIEXBUS_BAUDRATE, MODE_RXTX, JETIEXBUS_OPTIONS ); + serialSetMode(jetiExBusPort, MODE_RX); + return jetiExBusPort != NULL; +} + + +// Jeti Ex Bus crc calculations for single byte +uint16_t updateCRC16( uint16_t crc, uint8_t data ) +{ + uint16_t ret_val; + data ^= (uint8_t)(crc) & (uint8_t)(0xFF); + data ^= data << 4; + ret_val = ((((uint16_t)data << 8) | ((crc & 0xFF00) >> 8)) + ^ (uint8_t)(data >> 4) + ^ ((uint16_t)data << 3)); + return ret_val; +} + +// Jeti Ex Bus crc calculations for a frame +uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen) +{ + uint16_t crc16_data=0; + uint8_t mlen=0; + while(mlen>3; + } + break; + } +} + +void jetiExBusFrameReset(void) +{ + jetiExBusFramePosition = 0; + jetiExBusFrameLength = JETIEXBUS_MAX_FRAME_SIZE; +} + + +/* + supported: + 0x3E 0x01 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channeldata with telemetrie request (second byte 0x01) + 0x3E 0x03 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channeldata forbids answering (second byte 0x03) + 0x3D 0x01 0x08 Packet_ID 0x3A 0x00 CRC16 // Telemetrierequest EX telemetry (fifth byte 0x3A) + + other messages - not supported: + 0x3D 0x01 0x09 Packet_ID 0x3B 0x01 0xF0 CRC16 // Jetibox request (fifth byte 0x3B) + ... + +*/ +// Receive ISR callback +static void jetiExBusDataReceive(uint16_t c) +{ + uint32_t now; + static uint32_t jetiExBusTimeLast = 0; + static uint32_t jetiExBusTimeInterval; + static uint16_t crc = 0; + + // Check if we shall reset frame position due to time + now = millis(); + + jetiExBusTimeInterval = now - jetiExBusTimeLast; + jetiExBusTimeLast = now; + + if (jetiExBusTimeInterval > JETIEXBUS_MIN_FRAME_GAP) { + jetiExBusFrameReset(); + jetiExBusFrameState = EXBUS_STATE_ZERO; + jetiExBusRequestState = EXBUS_STATE_ZERO; + } + + // Check if we shall start a frame? + if (jetiExBusFramePosition == 0) { + switch(c){ + case JETIEXBUS_START_CHANNEL_FRAME: + jetiExBusFrameState = EXBUS_STATE_IN_PROGRESS; + jetiExBusFrame = &jetiExBusSerialFrame[0]; + break; + + case JETIEXBUS_START_REQUEST_FRAME: + jetiExBusRequestState = EXBUS_STATE_IN_PROGRESS; + jetiExBusFrame = &jetiExBusSerialFrame[JETIEXBUS_MAX_FRAME_SIZE]; + break; + + default: + return; + } + crc = 0; + } + + // Store in frame copy + jetiExBusFrame[jetiExBusFramePosition] = (uint8_t)c; + crc = updateCRC16(crc, (uint8_t)c); + jetiExBusFramePosition++; + + // Check the header for the messagelength + if (jetiExBusFramePosition==JETIEXBUS_HEADER_LEN) { + if ((jetiExBusFrame[EXBUS_HEADER_MSG_LEN]<=JETIEXBUS_MAX_FRAME_SIZE) && (jetiExBusFrame[EXBUS_HEADER_MSG_LEN]>=JETIEXBUS_MIN_FRAME_SIZE)) { + jetiExBusFrameLength = jetiExBusFrame[EXBUS_HEADER_MSG_LEN]; + } else { + jetiExBusFrameReset(); // not a valid frame + jetiExBusFrameState = EXBUS_STATE_ZERO; + jetiExBusRequestState = EXBUS_STATE_ZERO; + return; + } + } + + // Done? + if (jetiExBusFrameLength == jetiExBusFramePosition) { + if (crc == 0){ + if (jetiExBusFrameState == EXBUS_STATE_IN_PROGRESS) jetiExBusFrameState = EXBUS_STATE_RECEIVED; + if (jetiExBusRequestState == EXBUS_STATE_IN_PROGRESS) jetiExBusRequestState = EXBUS_STATE_RECEIVED; + } + jetiExBusFrameReset(); + } +} + +// Indicate time to read a frame from the data... +uint8_t jetiExBusFrameStatus(void) +{ + if (jetiExBusFrameState == EXBUS_STATE_RECEIVED) { + jetiExBusDecodeFrame(&jetiExBusSerialFrame[0]); + jetiExBusFrameState = EXBUS_STATE_ZERO; + } else { + return SERIAL_RX_FRAME_PENDING; + } + return SERIAL_RX_FRAME_COMPLETE; +} + + +static uint16_t jetiExBusReadRawRC(rxRuntimeConfig_t *rxRuntimeConfig, uint8_t chan) +{ + if (chan >= rxRuntimeConfig->channelCount) return 0; + + return (jetiExBusChannelData[chan]); +} + +#ifdef TELEMETRY +/* + ----------------------------------------------- + Jeti Ex Bus Telemetry + ----------------------------------------------- +*/ +void createExTelemetrieTextMessage(uint8_t *exMessage, uint8_t messageID, const exBusSensor_t *Sensor) +{ + uint8_t labelLength = strlen(Sensor->name); + uint8_t unitLength = strlen(Sensor->unit); + + jetiExTelemetry[EXTEL_HEADER_LSN_LB] = messageID & 0xF0; + + exMessage[EXTEL_HEADER_TYPE_LEN] = 8 + labelLength + unitLength; // 7 header, 1 CRC, label & unit + exMessage[EXTEL_HEADER_ID] = messageID & 0x0F; // ExMessage ID + exMessage[EXTEL_HEADER_DATA] = (labelLength << 3) + unitLength; + + memcpy(&exMessage[EXTEL_HEADER_DATA + 1], Sensor->name, labelLength); + memcpy(&exMessage[EXTEL_HEADER_DATA + 1 + labelLength], Sensor->unit, unitLength); + + exMessage[exMessage[EXTEL_HEADER_TYPE_LEN] + 1] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], exMessage[EXTEL_HEADER_TYPE_LEN]); +} + +uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) +{ + if ((itemStart % 16) == 0) itemStart++; + + uint8_t lastItem=itemStart + 5; + + if (lastItem > JETI_EX_SENSOR_COUNT) lastItem = JETI_EX_SENSOR_COUNT; + + jetiExTelemetry[EXTEL_HEADER_LSN_LB] = itemStart & 0xF0; + + if (itemStart>JETI_EX_SENSOR_COUNT) return 0; + + uint8_t byteCount = 0; + uint8_t valueByteCount = 0; + + for (uint8_t item=itemStart; item < lastItem; item++){ + + switch(jetiExSensors[item].exDataType) { + + case EX_TYPE_6b: + byteCount = 1; + break; + case EX_TYPE_14b: + byteCount = 2; + break; + case EX_TYPE_22b: + case EX_TYPE_DT: + byteCount = 3; + break; + case EX_TYPE_30b: + case EX_TYPE_GPS: + byteCount = 4; + break; + } + + exMessage[EXTEL_HEADER_ID + valueByteCount] = ((item & 0xF) << 4) + jetiExSensors[item].exDataType; + + + uint32_t value = jetiExSensors[item].value; + if (jetiExSensors[item].value < 0) value &= resetMask[byteCount - 1]; + value |= jetiExSensors[item].decimals; + + uint8_t iCount = 0; + do { + exMessage[EXTEL_HEADER_DATA + valueByteCount + iCount] = value; + value = value>>8; + iCount++; + } while(iCount < byteCount); + + valueByteCount += 1 + byteCount; + } + + exMessage[EXTEL_HEADER_TYPE_LEN] = 0x46+valueByteCount; + exMessage[(exMessage[EXTEL_HEADER_TYPE_LEN] & 0x3F) + 1] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], (exMessage[EXTEL_HEADER_TYPE_LEN]&0x3F)); + + return lastItem; +} + + + +void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t exBusID) +{ + exBusMessage[EXBUS_HEADER_PACKET_ID] = exBusID; + exBusMessage[EXBUS_HEADER_SUBLEN] = (exMessage[EXTEL_HEADER_TYPE_LEN] & 0x3F) + 2; // +2: startbyte & CRC8 + exBusMessage[EXBUS_HEADER_MSG_LEN] = 8 + exBusMessage[EXBUS_HEADER_SUBLEN]; + + uint16_t crc16 = calcCRC16(exBusMessage,exBusMessage[EXBUS_HEADER_MSG_LEN] - JETIEXBUS_CRC_LEN); + exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 2] = crc16; + exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 1] = crc16>>8; +} + + + +void initJetiExBusTelemetry(telemetryConfig_t *initialTelemetryConfig) +{ + UNUSED(initialTelemetryConfig); + + // Init Ex Bus Frame header + jetiExBusTelemetryFrame[EXBUS_HEADER_SYNC] = 0x3B; // Startbytes + jetiExBusTelemetryFrame[EXBUS_HEADER_REQ] = 0x01; + jetiExBusTelemetryFrame[EXBUS_HEADER_DATA_ID] = 0x3A; // Ex Telemetry + + + // Init Ex Telemetry header + jetiExTelemetry[EXTEL_HEADER_SYNC] = 0x9F; // Startbyte + jetiExTelemetry[EXTEL_HEADER_USN_LB] = 0x1E; // Serial Number 4 Byte + jetiExTelemetry[EXTEL_HEADER_USN_HB] = 0xA4; + jetiExTelemetry[EXTEL_HEADER_LSN_LB] = 0x00; // increment by telemetry count (%16) > only 15 values per device possible + jetiExTelemetry[EXTEL_HEADER_LSN_HB] = 0x00; + jetiExTelemetry[EXTEL_HEADER_RES] = 0x00; // Reserved by default 0x00 + + return; +} + + +void checkJetiExBusTelemetryState(void) +{ + return; +} + +void handleJetiExBusTelemetry(void) +{ + if (jetiExBusRequestState == EXBUS_STATE_RECEIVED) { + jetiExSensors[EX_VOLTAGE].value = vbat; + jetiExSensors[EX_CURRENT].value = amperage; + jetiExSensors[EX_ALTITUDE].value = BaroAlt; + jetiExSensors[EX_CAPACITY].value = mAhDrawn; + // switch to TX mode + if (uartTotalRxBytesWaiting(jetiExBusPort) == 0) { + serialSetMode(jetiExBusPort, MODE_TX); + jetiExBusTransceiveState = EXBUS_TRANS_TX; + sendJetiExBusTelemetry(jetiExBusSerialFrame[JETIEXBUS_FRAME_OFFSET + EXBUS_HEADER_PACKET_ID]); + jetiExBusRequestState = EXBUS_STATE_PROCESSED; + } + } + + // check the state if transmit is ready + if (jetiExBusTransceiveState == EXBUS_TRANS_TX_READY) { + uartPort_t *s = (uartPort_t*)jetiExBusPort; + if (uartTotalTxBytesFree(jetiExBusPort) == (s->port.txBufferSize - 1)) { // workaround for isUartTransmitBufferEmpty() + serialSetMode(jetiExBusPort, MODE_RX); + jetiExBusTransceiveState = EXBUS_TRANS_RX; + jetiExBusRequestState = EXBUS_STATE_ZERO; + } + } + return; +} + + + +void sendJetiExBusTelemetry(uint8_t packetID) +{ + static uint8_t sensorDescriptionCounter = 0; + static uint8_t sensorValueCounter = 1; + static uint8_t requestLoop = 0; + + + if (requestLoop == 100){ //every n request send a name of a value + if (sensorDescriptionCounter == JETI_EX_SENSOR_COUNT ) sensorDescriptionCounter = 0; + + createExTelemetrieTextMessage(jetiExTelemetry, sensorDescriptionCounter, &jetiExSensors[sensorDescriptionCounter]); + createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetry, packetID); + requestLoop = 0; + sensorDescriptionCounter++; + + } else { + if (sensorValueCounter >= JETI_EX_SENSOR_COUNT) sensorValueCounter = 1; + + sensorValueCounter = createExTelemetrieValueMessage(jetiExTelemetry, sensorValueCounter); + createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetry, packetID); + } + + for (uint8_t iCount = 0; iCount < jetiExBusTelemetryFrame[EXBUS_HEADER_MSG_LEN]; iCount++) { + serialWrite(jetiExBusPort, jetiExBusTelemetryFrame[iCount]); + } + jetiExBusTransceiveState = EXBUS_TRANS_TX_READY; + requestLoop++; +} + +#endif //TELEMETRY diff --git a/src/main/rx/jetiexbus.h b/src/main/rx/jetiexbus.h new file mode 100644 index 0000000000..a975e5c643 --- /dev/null +++ b/src/main/rx/jetiexbus.h @@ -0,0 +1,35 @@ +/* + * This file is part of Cleanflight. + * + * Cleanflight is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cleanflight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cleanflight. If not, see . + */ + +#pragma once + + +#include "rx/rx.h" + +bool jetiExBusInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback); +uint8_t jetiExBusFrameStatus(void); + + +#ifdef TELEMETRY + +#include "telemetry/telemetry.h" + +void initJetiExBusTelemetry(telemetryConfig_t *initialTelemetryConfig); +void checkJetiExBusTelemetryState(void); +void handleJetiExBusTelemetry(void); + +#endif //TELEMETRY diff --git a/src/main/rx/rx.c b/src/main/rx/rx.c index e2789f6d23..c4718f6685 100644 --- a/src/main/rx/rx.c +++ b/src/main/rx/rx.c @@ -50,6 +50,7 @@ #include "rx/msp.h" #include "rx/xbus.h" #include "rx/ibus.h" +#include "rx/jetiexbus.h" #include "rx/rx.h" @@ -240,6 +241,10 @@ void serialRxInit(rxConfig_t *rxConfig) rxRefreshRate = 20000; // TODO - Verify speed enabled = ibusInit(rxConfig, &rxRuntimeConfig, &rcReadRawFunc); break; + case SERIALRX_JETIEXBUS: + rxRefreshRate = 5500; + enabled = jetiExBusInit(rxConfig, &rxRuntimeConfig, &rcReadRawFunc); + break; } if (!enabled) { @@ -274,6 +279,8 @@ uint8_t serialRxFrameStatus(rxConfig_t *rxConfig) return xBusFrameStatus(); case SERIALRX_IBUS: return ibusFrameStatus(); + case SERIALRX_JETIEXBUS: + return jetiExBusFrameStatus(); } return SERIAL_RX_FRAME_PENDING; } diff --git a/src/main/rx/rx.h b/src/main/rx/rx.h index 6ac43194c6..d960d10eee 100644 --- a/src/main/rx/rx.h +++ b/src/main/rx/rx.h @@ -52,7 +52,8 @@ typedef enum { SERIALRX_XBUS_MODE_B = 5, SERIALRX_XBUS_MODE_B_RJ01 = 6, SERIALRX_IBUS = 7, - SERIALRX_PROVIDER_MAX = SERIALRX_IBUS + SERIALRX_JETIEXBUS = 8, + SERIALRX_PROVIDER_MAX = SERIALRX_JETIEXBUS } SerialRXType; #define SERIALRX_PROVIDER_COUNT (SERIALRX_PROVIDER_MAX + 1) diff --git a/src/main/telemetry/telemetry.c b/src/main/telemetry/telemetry.c index 4ac2713900..4963d9df6e 100644 --- a/src/main/telemetry/telemetry.c +++ b/src/main/telemetry/telemetry.c @@ -40,6 +40,7 @@ #include "telemetry/hott.h" #include "telemetry/smartport.h" #include "telemetry/ltm.h" +#include "rx/jetiexbus.h" static telemetryConfig_t *telemetryConfig; @@ -54,7 +55,8 @@ void telemetryInit(void) initHoTTTelemetry(telemetryConfig); initSmartPortTelemetry(telemetryConfig); initLtmTelemetry(telemetryConfig); - + initJetiExBusTelemetry(telemetryConfig); + telemetryCheckState(); } @@ -78,6 +80,7 @@ void telemetryCheckState(void) checkHoTTTelemetryState(); checkSmartPortTelemetryState(); checkLtmTelemetryState(); + checkJetiExBusTelemetryState(); } void telemetryProcess(rxConfig_t *rxConfig, uint16_t deadband3d_throttle) @@ -86,6 +89,7 @@ void telemetryProcess(rxConfig_t *rxConfig, uint16_t deadband3d_throttle) handleHoTTTelemetry(); handleSmartPortTelemetry(); handleLtmTelemetry(); + handleJetiExBusTelemetry(); } #endif From 0850e895505808b0b4aa618f562acfdf17863772 Mon Sep 17 00:00:00 2001 From: Thomas Miric Date: Thu, 21 Jan 2016 22:02:27 +0100 Subject: [PATCH 2/5] code formating and corrected spelling --- src/main/rx/jetiexbus.c | 104 ++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/main/rx/jetiexbus.c b/src/main/rx/jetiexbus.c index cdb6506103..7b1972bc42 100644 --- a/src/main/rx/jetiexbus.c +++ b/src/main/rx/jetiexbus.c @@ -78,8 +78,8 @@ #define JETIEXBUS_START_CHANNEL_FRAME (0x3E) #define JETIEXBUS_START_REQUEST_FRAME (0x3D) -#define EXBUS_CHANNELDATA (0x3E03) // Frame contains channeldata -#define EXBUS_CHANNELDATA_TELEMETRY_REQUEST (0x3E01) // Frame contains channeldata, but with a request for data +#define EXBUS_CHANNELDATA (0x3E03) // Frame contains Channel Data +#define EXBUS_CHANNELDATA_TELEMETRY_REQUEST (0x3E01) // Frame contains Channel Data, but with a request for data enum { @@ -140,13 +140,13 @@ typedef struct exBusSensor_s{ } exBusSensor_t; -#define SETMASK(decimals, bytes) (decimals<<((bytes*8)-3)) +#define SETMASK(decimals, bytes) (decimals << ((bytes*8)-3)) #define RESETMASK(bytes) (~(3 << ((bytes*8)-3))) const uint32_t resetMask[]={ RESETMASK(1), RESETMASK(2), RESETMASK(3), RESETMASK(4) }; // list of telemetry messages -// after 15 sensors must be a new Header : "CF-Dev 1.12 S2" +// after every 15 sensors a new header has to be inserted (e.g. "CF-Dev 1.12 S2") exBusSensor_t jetiExSensors[] = { { "CF-Dev 1.12 S1", "", 0, 0, 0 }, @@ -156,7 +156,6 @@ exBusSensor_t jetiExSensors[] = { { "Capacity", "mAh", 0, EX_TYPE_14b, SETMASK(0,2) } }; -// after 15 sensors a new enum value to be set: EX_NEW_SENSOR = 17 enum exSensors_e { EX_VOLTAGE = 1, EX_CURRENT, @@ -202,8 +201,6 @@ uint16_t updateCRC16( uint16_t crc, uint8_t data ); uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen); - - bool jetiExBusInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback) { UNUSED(rxConfig); @@ -228,7 +225,7 @@ bool jetiExBusInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcR } -// Jeti Ex Bus crc calculations for single byte +// Jeti Ex Bus CRC calculations for single byte uint16_t updateCRC16( uint16_t crc, uint8_t data ) { uint16_t ret_val; @@ -240,12 +237,12 @@ uint16_t updateCRC16( uint16_t crc, uint8_t data ) return ret_val; } -// Jeti Ex Bus crc calculations for a frame +// Jeti Ex Bus CRC calculations for a frame uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen) { - uint16_t crc16_data=0; - uint8_t mlen=0; - while(mlen>3; + jetiExBusChannelData[i] = value >> 3; } break; } @@ -311,12 +308,12 @@ void jetiExBusFrameReset(void) /* supported: - 0x3E 0x01 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channeldata with telemetrie request (second byte 0x01) - 0x3E 0x03 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channeldata forbids answering (second byte 0x03) - 0x3D 0x01 0x08 Packet_ID 0x3A 0x00 CRC16 // Telemetrierequest EX telemetry (fifth byte 0x3A) + 0x3E 0x01 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channel Data with telemetry request (2nd byte 0x01) + 0x3E 0x03 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channel Data forbids answering (2nd byte 0x03) + 0x3D 0x01 0x08 Packet_ID 0x3A 0x00 CRC16 // Telemetry Request EX telemetry (5th byte 0x3A) other messages - not supported: - 0x3D 0x01 0x09 Packet_ID 0x3B 0x01 0xF0 CRC16 // Jetibox request (fifth byte 0x3B) + 0x3D 0x01 0x09 Packet_ID 0x3B 0x01 0xF0 CRC16 // Jetibox request (5th byte 0x3B) ... */ @@ -364,7 +361,7 @@ static void jetiExBusDataReceive(uint16_t c) crc = updateCRC16(crc, (uint8_t)c); jetiExBusFramePosition++; - // Check the header for the messagelength + // Check the header for the message length if (jetiExBusFramePosition==JETIEXBUS_HEADER_LEN) { if ((jetiExBusFrame[EXBUS_HEADER_MSG_LEN]<=JETIEXBUS_MAX_FRAME_SIZE) && (jetiExBusFrame[EXBUS_HEADER_MSG_LEN]>=JETIEXBUS_MIN_FRAME_SIZE)) { jetiExBusFrameLength = jetiExBusFrame[EXBUS_HEADER_MSG_LEN]; @@ -386,7 +383,7 @@ static void jetiExBusDataReceive(uint16_t c) } } -// Indicate time to read a frame from the data... +// Check if it is time to read a frame from the data... uint8_t jetiExBusFrameStatus(void) { if (jetiExBusFrameState == EXBUS_STATE_RECEIVED) { @@ -401,7 +398,8 @@ uint8_t jetiExBusFrameStatus(void) static uint16_t jetiExBusReadRawRC(rxRuntimeConfig_t *rxRuntimeConfig, uint8_t chan) { - if (chan >= rxRuntimeConfig->channelCount) return 0; + if (chan >= rxRuntimeConfig->channelCount) + return 0; return (jetiExBusChannelData[chan]); } @@ -431,18 +429,27 @@ void createExTelemetrieTextMessage(uint8_t *exMessage, uint8_t messageID, const uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) { - if ((itemStart % 16) == 0) itemStart++; + uint8_t lastItem; + uint8_t byteCount = 0; + uint8_t valueByteCount = 0; + uint8_t iCount = 0; + uint32_t sensorValue; - uint8_t lastItem=itemStart + 5; - if (lastItem > JETI_EX_SENSOR_COUNT) lastItem = JETI_EX_SENSOR_COUNT; + if ((itemStart % 16) == 0) + itemStart++; + + lastItem = itemStart + 5; + + if (lastItem > JETI_EX_SENSOR_COUNT) + lastItem = JETI_EX_SENSOR_COUNT; jetiExTelemetry[EXTEL_HEADER_LSN_LB] = itemStart & 0xF0; - if (itemStart>JETI_EX_SENSOR_COUNT) return 0; + if (itemStart>JETI_EX_SENSOR_COUNT) + return 0; + - uint8_t byteCount = 0; - uint8_t valueByteCount = 0; for (uint8_t item=itemStart; item < lastItem; item++){ @@ -467,14 +474,16 @@ uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) exMessage[EXTEL_HEADER_ID + valueByteCount] = ((item & 0xF) << 4) + jetiExSensors[item].exDataType; - uint32_t value = jetiExSensors[item].value; - if (jetiExSensors[item].value < 0) value &= resetMask[byteCount - 1]; - value |= jetiExSensors[item].decimals; + sensorValue = jetiExSensors[item].value; + if (jetiExSensors[item].value < 0) + sensorValue &= resetMask[byteCount - 1]; - uint8_t iCount = 0; + sensorValue |= jetiExSensors[item].decimals; + + iCount = 0; do { - exMessage[EXTEL_HEADER_DATA + valueByteCount + iCount] = value; - value = value>>8; + exMessage[EXTEL_HEADER_DATA + valueByteCount + iCount] = sensorValue; + sensorValue = sensorValue>>8; iCount++; } while(iCount < byteCount); @@ -491,11 +500,13 @@ uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t exBusID) { + uint16_t crc16; + exBusMessage[EXBUS_HEADER_PACKET_ID] = exBusID; exBusMessage[EXBUS_HEADER_SUBLEN] = (exMessage[EXTEL_HEADER_TYPE_LEN] & 0x3F) + 2; // +2: startbyte & CRC8 exBusMessage[EXBUS_HEADER_MSG_LEN] = 8 + exBusMessage[EXBUS_HEADER_SUBLEN]; - uint16_t crc16 = calcCRC16(exBusMessage,exBusMessage[EXBUS_HEADER_MSG_LEN] - JETIEXBUS_CRC_LEN); + crc16 = calcCRC16(exBusMessage,exBusMessage[EXBUS_HEADER_MSG_LEN] - JETIEXBUS_CRC_LEN); exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 2] = crc16; exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 1] = crc16>>8; } @@ -518,7 +529,7 @@ void initJetiExBusTelemetry(telemetryConfig_t *initialTelemetryConfig) jetiExTelemetry[EXTEL_HEADER_USN_HB] = 0xA4; jetiExTelemetry[EXTEL_HEADER_LSN_LB] = 0x00; // increment by telemetry count (%16) > only 15 values per device possible jetiExTelemetry[EXTEL_HEADER_LSN_HB] = 0x00; - jetiExTelemetry[EXTEL_HEADER_RES] = 0x00; // Reserved by default 0x00 + jetiExTelemetry[EXTEL_HEADER_RES] = 0x00; // reserved, by default 0x00 return; } @@ -548,13 +559,12 @@ void handleJetiExBusTelemetry(void) // check the state if transmit is ready if (jetiExBusTransceiveState == EXBUS_TRANS_TX_READY) { uartPort_t *s = (uartPort_t*)jetiExBusPort; - if (uartTotalTxBytesFree(jetiExBusPort) == (s->port.txBufferSize - 1)) { // workaround for isUartTransmitBufferEmpty() + if (uartTotalTxBytesFree(jetiExBusPort) == (s->port.txBufferSize - 1)) { // workaround for 'isUartTransmitBufferEmpty()' serialSetMode(jetiExBusPort, MODE_RX); jetiExBusTransceiveState = EXBUS_TRANS_RX; jetiExBusRequestState = EXBUS_STATE_ZERO; } } - return; } @@ -566,8 +576,9 @@ void sendJetiExBusTelemetry(uint8_t packetID) static uint8_t requestLoop = 0; - if (requestLoop == 100){ //every n request send a name of a value - if (sensorDescriptionCounter == JETI_EX_SENSOR_COUNT ) sensorDescriptionCounter = 0; + if (requestLoop == 100){ //every nth request send the name of a value + if (sensorDescriptionCounter == JETI_EX_SENSOR_COUNT ) + sensorDescriptionCounter = 0; createExTelemetrieTextMessage(jetiExTelemetry, sensorDescriptionCounter, &jetiExSensors[sensorDescriptionCounter]); createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetry, packetID); @@ -575,7 +586,8 @@ void sendJetiExBusTelemetry(uint8_t packetID) sensorDescriptionCounter++; } else { - if (sensorValueCounter >= JETI_EX_SENSOR_COUNT) sensorValueCounter = 1; + if (sensorValueCounter >= JETI_EX_SENSOR_COUNT) + sensorValueCounter = 1; sensorValueCounter = createExTelemetrieValueMessage(jetiExTelemetry, sensorValueCounter); createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetry, packetID); From e985a6c60b0bd81a0e7ef9fbc321f21bb3f3f916 Mon Sep 17 00:00:00 2001 From: Thomas Miric Date: Fri, 22 Jan 2016 15:25:12 +0100 Subject: [PATCH 3/5] Change updateCRC8 with the optimized code from ledvinap --- src/main/rx/jetiexbus.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/src/main/rx/jetiexbus.c b/src/main/rx/jetiexbus.c index 7b1972bc42..dde86798f2 100644 --- a/src/main/rx/jetiexbus.c +++ b/src/main/rx/jetiexbus.c @@ -121,7 +121,6 @@ enum exTelHeader_e { EXTEL_HEADER_DATA }; - enum exDataType_e { EX_TYPE_6b = 0, // int6_t Data type 6b (-31 ¸31) EX_TYPE_14b = 1, // int14_t Data type 14b (-8191 ¸8191) @@ -237,6 +236,7 @@ uint16_t updateCRC16( uint16_t crc, uint8_t data ) return ret_val; } + // Jeti Ex Bus CRC calculations for a frame uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen) { @@ -254,14 +254,8 @@ uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen) // Jeti Ex Telemetry CRC calculations for single byte uint8_t updateCRC8( uint8_t crc, uint8_t data ) { - uint8_t crc_u; - - crc_u = crc; - crc_u ^= data; - for (uint8_t i = 0; i < 8; i++) { - crc_u = ( crc_u & 0x80 ) ? 0x07 ^ ( crc_u << 1 ) : ( crc_u << 1 ); - } - return crc_u; + crc ^= data; + return (crc ^ (crc << 1) ^ (crc << 2) ^ (0x0e090700 >> ((crc >> 3) & 0x18))); } // Jeti Ex Telemetry CRC calculations for a frame @@ -383,6 +377,7 @@ static void jetiExBusDataReceive(uint16_t c) } } + // Check if it is time to read a frame from the data... uint8_t jetiExBusFrameStatus(void) { @@ -427,6 +422,7 @@ void createExTelemetrieTextMessage(uint8_t *exMessage, uint8_t messageID, const exMessage[exMessage[EXTEL_HEADER_TYPE_LEN] + 1] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], exMessage[EXTEL_HEADER_TYPE_LEN]); } + uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) { uint8_t lastItem; @@ -449,8 +445,6 @@ uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) if (itemStart>JETI_EX_SENSOR_COUNT) return 0; - - for (uint8_t item=itemStart; item < lastItem; item++){ switch(jetiExSensors[item].exDataType) { @@ -497,7 +491,6 @@ uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) } - void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t exBusID) { uint16_t crc16; @@ -512,7 +505,6 @@ void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t exBus } - void initJetiExBusTelemetry(telemetryConfig_t *initialTelemetryConfig) { UNUSED(initialTelemetryConfig); @@ -540,6 +532,7 @@ void checkJetiExBusTelemetryState(void) return; } + void handleJetiExBusTelemetry(void) { if (jetiExBusRequestState == EXBUS_STATE_RECEIVED) { @@ -568,7 +561,6 @@ void handleJetiExBusTelemetry(void) } - void sendJetiExBusTelemetry(uint8_t packetID) { static uint8_t sensorDescriptionCounter = 0; From 08fb5bc1dd4e43abd3b210d04b1b0a389080d2ca Mon Sep 17 00:00:00 2001 From: Thomas Miric Date: Wed, 27 Jan 2016 19:58:10 +0100 Subject: [PATCH 4/5] rewrite some functions Some functions are rewritten to obtain a clearer code --- src/main/rx/jetiexbus.c | 498 +++++++++++++++++++++------------------- 1 file changed, 256 insertions(+), 242 deletions(-) diff --git a/src/main/rx/jetiexbus.c b/src/main/rx/jetiexbus.c index dde86798f2..d3ac730016 100644 --- a/src/main/rx/jetiexbus.c +++ b/src/main/rx/jetiexbus.c @@ -36,7 +36,9 @@ #include #include +#include +#include "common/utils.h" #include "platform.h" #include "build_config.h" #include "drivers/system.h" @@ -56,31 +58,32 @@ #endif //TELEMETRY + +#include "debug.h" #include "rx/rx.h" // // Serial driver for Jeti EX Bus receiver // -#define JETIEXBUS_BAUDRATE 125000 // EX Bus 125000; EX Bus HS 250000 not supported -#define JETIEXBUS_OPTIONS (SERIAL_STOPBITS_1 | SERIAL_PARITY_NO | SERIAL_NOT_INVERTED ) +#define JETIEXBUS_BAUDRATE 125000 // EX Bus 125000; EX Bus HS 250000 not supported +#define JETIEXBUS_OPTIONS (SERIAL_STOPBITS_1 | SERIAL_PARITY_NO | SERIAL_NOT_INVERTED) +#define JETIEXBUS_MIN_FRAME_GAP 1000 +#define JETIEXBUS_CHANNEL_COUNT 16 // most Jeti TX transmit 16 channels -#define JETIEXBUS_MIN_FRAME_GAP 1 +#define EXBUS_HEADER_LEN 6 +#define EXBUS_CRC_LEN 2 +#define EXBUS_OVERHEAD (EXBUS_HEADER_LEN + EXBUS_CRC_LEN) +#define EXBUS_MAX_CHANNEL_FRAME_SIZE (EXBUS_HEADER_LEN + JETIEXBUS_CHANNEL_COUNT*2 + EXBUS_CRC_LEN) +#define EXBUS_MAX_REQUEST_FRAME_SIZE 9 -#define JETIEXBUS_CHANNEL_COUNT 16 // most Jeti TX transmit 16 channels -#define JETIEXBUS_MIN_FRAME_SIZE 8 -#define JETIEXBUS_HEADER_LEN 6 -#define JETIEXBUS_CRC_LEN 2 - -#define JETIEXBUS_MAX_FRAME_SIZE (JETIEXBUS_HEADER_LEN + JETIEXBUS_CHANNEL_COUNT*2 + JETIEXBUS_CRC_LEN) -#define JETIEXBUS_FRAME_OFFSET (JETIEXBUS_MAX_FRAME_SIZE) -#define JETIEXBUS_MAX_REQUESTFRAME_SIZE 8 - -#define JETIEXBUS_START_CHANNEL_FRAME (0x3E) -#define JETIEXBUS_START_REQUEST_FRAME (0x3D) - -#define EXBUS_CHANNELDATA (0x3E03) // Frame contains Channel Data -#define EXBUS_CHANNELDATA_TELEMETRY_REQUEST (0x3E01) // Frame contains Channel Data, but with a request for data +#define EXBUS_START_CHANNEL_FRAME (0x3E) +#define EXBUS_START_REQUEST_FRAME (0x3D) +#define EXBUS_EX_REQUEST (0x3A) +#define EXBUS_JETIBOX_REQUEST (0x3B) +#define EXBUS_CHANNELDATA (0x3E03) // Frame contains Channel Data +#define EXBUS_CHANNELDATA_DATA_REQUEST (0x3E01) // Frame contains Channel Data, but with a request for data +#define EXBUS_TELEMETRY_REQUEST (0x3D01) // Frame is a request Frame enum { EXBUS_STATE_ZERO = 0, @@ -93,7 +96,7 @@ enum { EXBUS_TRANS_ZERO = 0, EXBUS_TRANS_RX_READY, EXBUS_TRANS_RX, - EXBUS_TRANS_TX_READY, + EXBUS_TRANS_IS_TX_COMPLETED, EXBUS_TRANS_TX }; @@ -109,6 +112,16 @@ enum exBusHeader_e { #ifdef TELEMETRY +#define EXTEL_DATA_MSG (0x40) +#define EXTEL_UNMASK_TYPE (0x3F) +#define EXTEL_SYNC_LEN 1 +#define EXTEL_CRC_LEN 1 +#define EXTEL_HEADER_LEN 6 +#define EXTEL_MAX_LEN 29 +#define EXTEL_OVERHEAD (EXTEL_SYNC_LEN + EXTEL_HEADER_LEN + EXTEL_CRC_LEN) +#define EXTEL_MAX_PAYLOAD (EXTEL_MAX_LEN - EXTEL_OVERHEAD) +#define EXBUS_MAX_REQUEST_BUFFER_SIZE (EXBUS_OVERHEAD + EXTEL_MAX_LEN) + enum exTelHeader_e { EXTEL_HEADER_SYNC = 0, EXTEL_HEADER_TYPE_LEN, @@ -130,162 +143,156 @@ enum exDataType_e { EX_TYPE_GPS = 9 // int30_t Special data type – GPS coordinates: lo/hi minute - lo/hi degree. }; +const uint8_t exDataTypeLen[]={ + [EX_TYPE_6b] = 1, + [EX_TYPE_14b] = 2, + [EX_TYPE_22b] = 3, + [EX_TYPE_DT] = 3, + [EX_TYPE_30b] = 4, + [EX_TYPE_GPS] = 4 +}; + typedef struct exBusSensor_s{ - const char *name; + const char *label; const char *unit; int32_t value; const uint8_t exDataType; - const uint32_t decimals; + const uint8_t decimals; } exBusSensor_t; - -#define SETMASK(decimals, bytes) (decimals << ((bytes*8)-3)) -#define RESETMASK(bytes) (~(3 << ((bytes*8)-3))) - -const uint32_t resetMask[]={ RESETMASK(1), RESETMASK(2), RESETMASK(3), RESETMASK(4) }; +#define DECIMAL_MASK(decimals) (decimals << 5) // list of telemetry messages // after every 15 sensors a new header has to be inserted (e.g. "CF-Dev 1.12 S2") - exBusSensor_t jetiExSensors[] = { - { "CF-Dev 1.12 S1", "", 0, 0, 0 }, - { "Voltage", "V", 0, EX_TYPE_14b, SETMASK(1,2) }, - { "Current", "A", 0, EX_TYPE_14b, SETMASK(2,2) }, - { "Altitude", "m", 0, EX_TYPE_14b, SETMASK(1,2) }, - { "Capacity", "mAh", 0, EX_TYPE_14b, SETMASK(0,2) } + { "CF-Dev 1.12 S1", "", 0, 0, 0 }, // device descripton + { "Voltage", "V", 0, EX_TYPE_14b, DECIMAL_MASK(1) }, + { "Current", "A", 0, EX_TYPE_14b, DECIMAL_MASK(2) }, + { "Altitude", "m", 0, EX_TYPE_14b, DECIMAL_MASK(1) }, + { "Capacity", "mAh", 0, EX_TYPE_22b, DECIMAL_MASK(0) }, + { "frames lost", " ", 0, EX_TYPE_22b, DECIMAL_MASK(0) }, // for debug only + { "time Diff", "us", 0, EX_TYPE_14b, DECIMAL_MASK(0) } // for debug only }; + +// after every 15 sensors increment the step by 2 (e.g. ...EX_VAL15, EX_VAL16 = 17) to skip the device description enum exSensors_e { EX_VOLTAGE = 1, EX_CURRENT, EX_ALTITUDE, - EX_CAPACITY + EX_CAPACITY, + EX_FRAMES_LOST, // for debug only + EX_TIME_DIFF // for debug only }; -#define JETI_EX_SENSOR_COUNT (sizeof(jetiExSensors) / sizeof(exBusSensor_t)) - +#define JETI_EX_SENSOR_COUNT (ARRAYLEN(jetiExSensors)) #endif //TELEMETRY static serialPort_t *jetiExBusPort; -static serialPortConfig_t *portConfig; -static uint8_t jetiExBusFrameState = EXBUS_STATE_ZERO; -static uint8_t jetiExBusRequestState = EXBUS_STATE_ZERO; +static uint32_t jetiTimeStampRequest = 0; + static uint8_t jetiExBusFramePosition; static uint8_t jetiExBusFrameLength; -// Use max values for ram areas -static uint8_t jetiExBusSerialFrame[JETIEXBUS_MAX_FRAME_SIZE+JETIEXBUS_MAX_REQUESTFRAME_SIZE]; -static uint8_t *jetiExBusFrame; +static uint8_t jetiExBusFrameState = EXBUS_STATE_ZERO; +static uint8_t jetiExBusRequestState = EXBUS_STATE_ZERO; +// Use max values for ram areas +static uint8_t jetiExBusChannelFrame[EXBUS_MAX_CHANNEL_FRAME_SIZE]; +static uint8_t jetiExBusRequestFrame[EXBUS_MAX_REQUEST_FRAME_SIZE]; static uint16_t jetiExBusChannelData[JETIEXBUS_CHANNEL_COUNT]; static void jetiExBusDataReceive(uint16_t c); static uint16_t jetiExBusReadRawRC(rxRuntimeConfig_t *rxRuntimeConfig, uint8_t chan); +static void jetiExBusFrameReset(); #ifdef TELEMETRY -static uint8_t jetiExBusTelemetryFrame[JETIEXBUS_MAX_FRAME_SIZE]; +static uint8_t jetiExBusTelemetryFrame[40]; static uint8_t jetiExBusTransceiveState = EXBUS_TRANS_RX; -static uint8_t *jetiExTelemetry=&jetiExBusTelemetryFrame[EXBUS_HEADER_DATA]; static void sendJetiExBusTelemetry(uint8_t packetID); -uint8_t updateCRC8( uint8_t crc, uint8_t data ); uint8_t calcCRC8(uint8_t *pt, uint8_t msgLen); #endif //TELEMETRY -uint16_t updateCRC16( uint16_t crc, uint8_t data ); uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen); bool jetiExBusInit(rxConfig_t *rxConfig, rxRuntimeConfig_t *rxRuntimeConfig, rcReadRawDataPtr *callback) { UNUSED(rxConfig); - + serialPortConfig_t *portConfig; + if (callback) { *callback = jetiExBusReadRawRC; } rxRuntimeConfig->channelCount = JETIEXBUS_CHANNEL_COUNT; - jetiExBusFramePosition = 0; - jetiExBusFrameLength = JETIEXBUS_MAX_FRAME_SIZE; + jetiExBusFrameReset(); portConfig = findSerialPortConfig(FUNCTION_RX_SERIAL); - + if (!portConfig) { return false; } - + jetiExBusPort = openSerialPort(portConfig->identifier, FUNCTION_RX_SERIAL, jetiExBusDataReceive, JETIEXBUS_BAUDRATE, MODE_RXTX, JETIEXBUS_OPTIONS ); serialSetMode(jetiExBusPort, MODE_RX); return jetiExBusPort != NULL; } -// Jeti Ex Bus CRC calculations for single byte -uint16_t updateCRC16( uint16_t crc, uint8_t data ) -{ - uint16_t ret_val; - data ^= (uint8_t)(crc) & (uint8_t)(0xFF); - data ^= data << 4; - ret_val = ((((uint16_t)data << 8) | ((crc & 0xFF00) >> 8)) - ^ (uint8_t)(data >> 4) - ^ ((uint16_t)data << 3)); - return ret_val; -} - - // Jeti Ex Bus CRC calculations for a frame uint16_t calcCRC16(uint8_t *pt, uint8_t msgLen) { uint16_t crc16_data = 0; - uint8_t mlen = 0; - while(mlen < msgLen) { - crc16_data = updateCRC16(crc16_data, pt[mlen]); - mlen++; + uint8_t data=0; + + for (uint8_t mlen = 0; mlen < msgLen; mlen++){ + data = pt[mlen] ^ ((uint8_t)(crc16_data) & (uint8_t)(0xFF)); + data ^= data << 4; + crc16_data = ((((uint16_t)data << 8) | ((crc16_data & 0xFF00) >> 8)) + ^ (uint8_t)(data >> 4) + ^ ((uint16_t)data << 3)); } return(crc16_data); } #ifdef TELEMETRY -// Jeti Ex Telemetry CRC calculations for single byte -uint8_t updateCRC8( uint8_t crc, uint8_t data ) -{ - crc ^= data; - return (crc ^ (crc << 1) ^ (crc << 2) ^ (0x0e090700 >> ((crc >> 3) & 0x18))); -} // Jeti Ex Telemetry CRC calculations for a frame uint8_t calcCRC8(uint8_t *pt, uint8_t msgLen) { - uint8_t crc8_data = 0; - uint8_t mlen = 0; - for (mlen = 0; mlen < msgLen; mlen++) { - crc8_data = updateCRC8(crc8_data, pt[mlen]); + uint8_t crc=0; + + for (uint8_t mlen = 0; mlen < msgLen; mlen++) { + crc ^= pt[mlen]; + crc = crc ^ (crc << 1) ^ (crc << 2) ^ (0x0e090700 >> ((crc >> 3) & 0x18)); } - return(crc8_data); + return(crc); } #endif //TELEMETRY -void jetiExBusDecodeFrame(uint8_t *pFrame) +void jetiExBusDecodeChannelFrame(uint8_t *exBusFrame) { uint16_t value; uint8_t frameAddr; // Decode header - switch (((uint16_t)jetiExBusFrame[EXBUS_HEADER_SYNC] << 8) + ((uint16_t)jetiExBusFrame[EXBUS_HEADER_REQ])){ + switch (((uint16_t)exBusFrame[EXBUS_HEADER_SYNC] << 8) | ((uint16_t)exBusFrame[EXBUS_HEADER_REQ])){ - case EXBUS_CHANNELDATA_TELEMETRY_REQUEST: // not yet specified + case EXBUS_CHANNELDATA_DATA_REQUEST: // not yet specified case EXBUS_CHANNELDATA: for (uint8_t i = 0; i < JETIEXBUS_CHANNEL_COUNT; i++) { - frameAddr = JETIEXBUS_HEADER_LEN + i * 2; - value = ((uint16_t)pFrame[frameAddr + 1]) << 8; - value += (uint16_t)pFrame[frameAddr]; + frameAddr = EXBUS_HEADER_LEN + i * 2; + value = ((uint16_t)exBusFrame[frameAddr + 1]) << 8; + value += (uint16_t)exBusFrame[frameAddr]; // Convert to internal format jetiExBusChannelData[i] = value >> 3; } @@ -293,10 +300,11 @@ void jetiExBusDecodeFrame(uint8_t *pFrame) } } -void jetiExBusFrameReset(void) + +void jetiExBusFrameReset() { jetiExBusFramePosition = 0; - jetiExBusFrameLength = JETIEXBUS_MAX_FRAME_SIZE; + jetiExBusFrameLength = EXBUS_MAX_CHANNEL_FRAME_SIZE; } @@ -305,22 +313,23 @@ void jetiExBusFrameReset(void) 0x3E 0x01 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channel Data with telemetry request (2nd byte 0x01) 0x3E 0x03 LEN Packet_ID 0x31 SUB_LEN Data_array CRC16 // Channel Data forbids answering (2nd byte 0x03) 0x3D 0x01 0x08 Packet_ID 0x3A 0x00 CRC16 // Telemetry Request EX telemetry (5th byte 0x3A) - + other messages - not supported: 0x3D 0x01 0x09 Packet_ID 0x3B 0x01 0xF0 CRC16 // Jetibox request (5th byte 0x3B) ... - */ + // Receive ISR callback static void jetiExBusDataReceive(uint16_t c) { uint32_t now; static uint32_t jetiExBusTimeLast = 0; - static uint32_t jetiExBusTimeInterval; - static uint16_t crc = 0; - + static int32_t jetiExBusTimeInterval; + + static uint8_t *jetiExBusFrame; + // Check if we shall reset frame position due to time - now = millis(); + now = micros(); jetiExBusTimeInterval = now - jetiExBusTimeLast; jetiExBusTimeLast = now; @@ -330,64 +339,76 @@ static void jetiExBusDataReceive(uint16_t c) jetiExBusFrameState = EXBUS_STATE_ZERO; jetiExBusRequestState = EXBUS_STATE_ZERO; } - + // Check if we shall start a frame? if (jetiExBusFramePosition == 0) { switch(c){ - case JETIEXBUS_START_CHANNEL_FRAME: + case EXBUS_START_CHANNEL_FRAME: jetiExBusFrameState = EXBUS_STATE_IN_PROGRESS; - jetiExBusFrame = &jetiExBusSerialFrame[0]; + jetiExBusFrame = jetiExBusChannelFrame; break; - - case JETIEXBUS_START_REQUEST_FRAME: + + case EXBUS_START_REQUEST_FRAME: jetiExBusRequestState = EXBUS_STATE_IN_PROGRESS; - jetiExBusFrame = &jetiExBusSerialFrame[JETIEXBUS_MAX_FRAME_SIZE]; + jetiExBusFrame = jetiExBusRequestFrame; break; default: return; } - crc = 0; } // Store in frame copy jetiExBusFrame[jetiExBusFramePosition] = (uint8_t)c; - crc = updateCRC16(crc, (uint8_t)c); jetiExBusFramePosition++; - + // Check the header for the message length - if (jetiExBusFramePosition==JETIEXBUS_HEADER_LEN) { - if ((jetiExBusFrame[EXBUS_HEADER_MSG_LEN]<=JETIEXBUS_MAX_FRAME_SIZE) && (jetiExBusFrame[EXBUS_HEADER_MSG_LEN]>=JETIEXBUS_MIN_FRAME_SIZE)) { + if (jetiExBusFramePosition == EXBUS_HEADER_LEN) { + + if((jetiExBusFrameState == EXBUS_STATE_IN_PROGRESS) && (jetiExBusFrame[EXBUS_HEADER_MSG_LEN] <= EXBUS_MAX_CHANNEL_FRAME_SIZE)) { jetiExBusFrameLength = jetiExBusFrame[EXBUS_HEADER_MSG_LEN]; - } else { - jetiExBusFrameReset(); // not a valid frame - jetiExBusFrameState = EXBUS_STATE_ZERO; - jetiExBusRequestState = EXBUS_STATE_ZERO; return; } + + if((jetiExBusRequestState == EXBUS_STATE_IN_PROGRESS) && (jetiExBusFrame[EXBUS_HEADER_MSG_LEN] <= EXBUS_MAX_REQUEST_FRAME_SIZE)) { + jetiExBusFrameLength = jetiExBusFrame[EXBUS_HEADER_MSG_LEN]; + return; + } + + jetiExBusFrameReset(); // not a valid frame + jetiExBusFrameState = EXBUS_STATE_ZERO; + jetiExBusRequestState = EXBUS_STATE_ZERO; + return; } // Done? if (jetiExBusFrameLength == jetiExBusFramePosition) { - if (crc == 0){ - if (jetiExBusFrameState == EXBUS_STATE_IN_PROGRESS) jetiExBusFrameState = EXBUS_STATE_RECEIVED; - if (jetiExBusRequestState == EXBUS_STATE_IN_PROGRESS) jetiExBusRequestState = EXBUS_STATE_RECEIVED; + if (jetiExBusFrameState == EXBUS_STATE_IN_PROGRESS) + jetiExBusFrameState = EXBUS_STATE_RECEIVED; + if (jetiExBusRequestState == EXBUS_STATE_IN_PROGRESS) { + jetiExBusRequestState = EXBUS_STATE_RECEIVED; + jetiTimeStampRequest = micros(); } + jetiExBusFrameReset(); } } // Check if it is time to read a frame from the data... -uint8_t jetiExBusFrameStatus(void) +uint8_t jetiExBusFrameStatus() { - if (jetiExBusFrameState == EXBUS_STATE_RECEIVED) { - jetiExBusDecodeFrame(&jetiExBusSerialFrame[0]); + if (jetiExBusFrameState != EXBUS_STATE_RECEIVED) + return SERIAL_RX_FRAME_PENDING; + + if(calcCRC16(jetiExBusChannelFrame, jetiExBusChannelFrame[EXBUS_HEADER_MSG_LEN]) == 0) { + jetiExBusDecodeChannelFrame(jetiExBusChannelFrame); jetiExBusFrameState = EXBUS_STATE_ZERO; + return SERIAL_RX_FRAME_COMPLETE; } else { + jetiExBusFrameState = EXBUS_STATE_ZERO; return SERIAL_RX_FRAME_PENDING; } - return SERIAL_RX_FRAME_COMPLETE; } @@ -399,111 +420,13 @@ static uint16_t jetiExBusReadRawRC(rxRuntimeConfig_t *rxRuntimeConfig, uint8_t c return (jetiExBusChannelData[chan]); } + #ifdef TELEMETRY /* ----------------------------------------------- Jeti Ex Bus Telemetry ----------------------------------------------- */ -void createExTelemetrieTextMessage(uint8_t *exMessage, uint8_t messageID, const exBusSensor_t *Sensor) -{ - uint8_t labelLength = strlen(Sensor->name); - uint8_t unitLength = strlen(Sensor->unit); - - jetiExTelemetry[EXTEL_HEADER_LSN_LB] = messageID & 0xF0; - - exMessage[EXTEL_HEADER_TYPE_LEN] = 8 + labelLength + unitLength; // 7 header, 1 CRC, label & unit - exMessage[EXTEL_HEADER_ID] = messageID & 0x0F; // ExMessage ID - exMessage[EXTEL_HEADER_DATA] = (labelLength << 3) + unitLength; - - memcpy(&exMessage[EXTEL_HEADER_DATA + 1], Sensor->name, labelLength); - memcpy(&exMessage[EXTEL_HEADER_DATA + 1 + labelLength], Sensor->unit, unitLength); - - exMessage[exMessage[EXTEL_HEADER_TYPE_LEN] + 1] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], exMessage[EXTEL_HEADER_TYPE_LEN]); -} - - -uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) -{ - uint8_t lastItem; - uint8_t byteCount = 0; - uint8_t valueByteCount = 0; - uint8_t iCount = 0; - uint32_t sensorValue; - - - if ((itemStart % 16) == 0) - itemStart++; - - lastItem = itemStart + 5; - - if (lastItem > JETI_EX_SENSOR_COUNT) - lastItem = JETI_EX_SENSOR_COUNT; - - jetiExTelemetry[EXTEL_HEADER_LSN_LB] = itemStart & 0xF0; - - if (itemStart>JETI_EX_SENSOR_COUNT) - return 0; - - for (uint8_t item=itemStart; item < lastItem; item++){ - - switch(jetiExSensors[item].exDataType) { - - case EX_TYPE_6b: - byteCount = 1; - break; - case EX_TYPE_14b: - byteCount = 2; - break; - case EX_TYPE_22b: - case EX_TYPE_DT: - byteCount = 3; - break; - case EX_TYPE_30b: - case EX_TYPE_GPS: - byteCount = 4; - break; - } - - exMessage[EXTEL_HEADER_ID + valueByteCount] = ((item & 0xF) << 4) + jetiExSensors[item].exDataType; - - - sensorValue = jetiExSensors[item].value; - if (jetiExSensors[item].value < 0) - sensorValue &= resetMask[byteCount - 1]; - - sensorValue |= jetiExSensors[item].decimals; - - iCount = 0; - do { - exMessage[EXTEL_HEADER_DATA + valueByteCount + iCount] = sensorValue; - sensorValue = sensorValue>>8; - iCount++; - } while(iCount < byteCount); - - valueByteCount += 1 + byteCount; - } - - exMessage[EXTEL_HEADER_TYPE_LEN] = 0x46+valueByteCount; - exMessage[(exMessage[EXTEL_HEADER_TYPE_LEN] & 0x3F) + 1] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], (exMessage[EXTEL_HEADER_TYPE_LEN]&0x3F)); - - return lastItem; -} - - -void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t exBusID) -{ - uint16_t crc16; - - exBusMessage[EXBUS_HEADER_PACKET_ID] = exBusID; - exBusMessage[EXBUS_HEADER_SUBLEN] = (exMessage[EXTEL_HEADER_TYPE_LEN] & 0x3F) + 2; // +2: startbyte & CRC8 - exBusMessage[EXBUS_HEADER_MSG_LEN] = 8 + exBusMessage[EXBUS_HEADER_SUBLEN]; - - crc16 = calcCRC16(exBusMessage,exBusMessage[EXBUS_HEADER_MSG_LEN] - JETIEXBUS_CRC_LEN); - exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 2] = crc16; - exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 1] = crc16>>8; -} - void initJetiExBusTelemetry(telemetryConfig_t *initialTelemetryConfig) { @@ -516,14 +439,87 @@ void initJetiExBusTelemetry(telemetryConfig_t *initialTelemetryConfig) // Init Ex Telemetry header - jetiExTelemetry[EXTEL_HEADER_SYNC] = 0x9F; // Startbyte - jetiExTelemetry[EXTEL_HEADER_USN_LB] = 0x1E; // Serial Number 4 Byte - jetiExTelemetry[EXTEL_HEADER_USN_HB] = 0xA4; - jetiExTelemetry[EXTEL_HEADER_LSN_LB] = 0x00; // increment by telemetry count (%16) > only 15 values per device possible - jetiExTelemetry[EXTEL_HEADER_LSN_HB] = 0x00; - jetiExTelemetry[EXTEL_HEADER_RES] = 0x00; // reserved, by default 0x00 + uint8_t *jetiExTelemetryFrame = &jetiExBusTelemetryFrame[EXBUS_HEADER_DATA]; + jetiExTelemetryFrame[EXTEL_HEADER_SYNC] = 0x9F; // Startbyte + jetiExTelemetryFrame[EXTEL_HEADER_USN_LB] = 0x1E; // Serial Number 4 Byte + jetiExTelemetryFrame[EXTEL_HEADER_USN_HB] = 0xA4; + jetiExTelemetryFrame[EXTEL_HEADER_LSN_LB] = 0x00; // increment by telemetry count (%16) > only 15 values per device possible + jetiExTelemetryFrame[EXTEL_HEADER_LSN_HB] = 0x00; + jetiExTelemetryFrame[EXTEL_HEADER_RES] = 0x00; // reserved, by default 0x00 +} - return; + +void createExTelemetrieTextMessage(uint8_t *exMessage, uint8_t messageID, const exBusSensor_t *sensor) +{ + uint8_t labelLength = strlen(sensor->label); + uint8_t unitLength = strlen(sensor->unit); + + exMessage[EXTEL_HEADER_TYPE_LEN] = EXTEL_OVERHEAD + labelLength + unitLength; + exMessage[EXTEL_HEADER_LSN_LB] = messageID & 0xF0; // Device ID + exMessage[EXTEL_HEADER_ID] = messageID & 0x0F; // Sensor ID (%16) + exMessage[EXTEL_HEADER_DATA] = (labelLength << 3) + unitLength; + + memcpy(&exMessage[EXTEL_HEADER_DATA + 1], sensor->label, labelLength); + memcpy(&exMessage[EXTEL_HEADER_DATA + 1 + labelLength], sensor->unit, unitLength); + + exMessage[exMessage[EXTEL_HEADER_TYPE_LEN] + EXTEL_CRC_LEN] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], exMessage[EXTEL_HEADER_TYPE_LEN]); +} + + +uint8_t createExTelemetrieValueMessage(uint8_t *exMessage, uint8_t itemStart) +{ + uint8_t item = itemStart; + uint8_t iCount; + uint8_t messageSize; + uint32_t sensorValue; + + if ((item & 0x0F) == 0) + item++; + + if(item >= JETI_EX_SENSOR_COUNT) + item = 1; + + exMessage[EXTEL_HEADER_LSN_LB] = item & 0xF0; // Device ID + uint8_t *p = &exMessage[EXTEL_HEADER_ID]; + + while(item <= (itemStart | 0x0F)) { + *p++ = ((item & 0x0F) << 4) | jetiExSensors[item].exDataType; // Sensor ID (%16) | EX Data Type + + sensorValue = jetiExSensors[item].value; + iCount = exDataTypeLen[jetiExSensors[item].exDataType]; + while(iCount > 1) { + *p++ = sensorValue; + sensorValue = sensorValue >> 8; + iCount--; + } + *p++ = (sensorValue & 0x9F) | jetiExSensors[item].decimals; + + item++; + if(item > JETI_EX_SENSOR_COUNT) + break; + if(EXTEL_MAX_PAYLOAD <= ((p-&exMessage[EXTEL_HEADER_ID]) + exDataTypeLen[jetiExSensors[item].exDataType]) + 1) + break; + } + + messageSize = (EXTEL_HEADER_LEN + (p-&exMessage[EXTEL_HEADER_ID])); + exMessage[EXTEL_HEADER_TYPE_LEN] = EXTEL_DATA_MSG | messageSize; + exMessage[messageSize + EXTEL_CRC_LEN] = calcCRC8(&exMessage[EXTEL_HEADER_TYPE_LEN], messageSize); + + return item; // return the next item +} + + +void createExBusMessage(uint8_t *exBusMessage, uint8_t *exMessage, uint8_t packetID) +{ + uint16_t crc16; + + exBusMessage[EXBUS_HEADER_PACKET_ID] = packetID; + exBusMessage[EXBUS_HEADER_SUBLEN] = (exMessage[EXTEL_HEADER_TYPE_LEN] & EXTEL_UNMASK_TYPE) + 2; // +2: startbyte & CRC8 + exBusMessage[EXBUS_HEADER_MSG_LEN] = EXBUS_OVERHEAD + exBusMessage[EXBUS_HEADER_SUBLEN]; + + crc16 = calcCRC16(exBusMessage, exBusMessage[EXBUS_HEADER_MSG_LEN] - EXBUS_CRC_LEN); + exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 2] = crc16; + exBusMessage[exBusMessage[EXBUS_HEADER_MSG_LEN] - 1] = crc16 >> 8; } @@ -535,24 +531,45 @@ void checkJetiExBusTelemetryState(void) void handleJetiExBusTelemetry(void) { + static uint16_t framesLost = 0; // only for debug + uint32_t timeDiff; + // Check if we shall reset frame position due to time + if (jetiExBusRequestState == EXBUS_STATE_RECEIVED) { - jetiExSensors[EX_VOLTAGE].value = vbat; - jetiExSensors[EX_CURRENT].value = amperage; - jetiExSensors[EX_ALTITUDE].value = BaroAlt; - jetiExSensors[EX_CAPACITY].value = mAhDrawn; - // switch to TX mode - if (uartTotalRxBytesWaiting(jetiExBusPort) == 0) { - serialSetMode(jetiExBusPort, MODE_TX); - jetiExBusTransceiveState = EXBUS_TRANS_TX; - sendJetiExBusTelemetry(jetiExBusSerialFrame[JETIEXBUS_FRAME_OFFSET + EXBUS_HEADER_PACKET_ID]); - jetiExBusRequestState = EXBUS_STATE_PROCESSED; + + // to prevent timing issues from request to answer - max. 4ms + timeDiff = micros() - jetiTimeStampRequest; + + if(timeDiff > 3000) { // include reserved time + jetiExBusRequestState = EXBUS_STATE_ZERO; + framesLost++; + return; + } + + if((jetiExBusRequestFrame[EXBUS_HEADER_DATA_ID] == EXBUS_EX_REQUEST) && (calcCRC16(jetiExBusRequestFrame, jetiExBusRequestFrame[EXBUS_HEADER_MSG_LEN]) == 0)) { + jetiExSensors[EX_VOLTAGE].value = vbat; + jetiExSensors[EX_CURRENT].value = amperage; + jetiExSensors[EX_ALTITUDE].value = BaroAlt; + jetiExSensors[EX_CAPACITY].value = mAhDrawn; + jetiExSensors[EX_FRAMES_LOST].value = framesLost; + jetiExSensors[EX_TIME_DIFF].value = timeDiff; + + // switch to TX mode + if (uartTotalRxBytesWaiting(jetiExBusPort) == 0) { + serialSetMode(jetiExBusPort, MODE_TX); + jetiExBusTransceiveState = EXBUS_TRANS_TX; + sendJetiExBusTelemetry(jetiExBusRequestFrame[EXBUS_HEADER_PACKET_ID]); + jetiExBusRequestState = EXBUS_STATE_PROCESSED; + } + } else { + jetiExBusRequestState = EXBUS_STATE_ZERO; + return; } } // check the state if transmit is ready - if (jetiExBusTransceiveState == EXBUS_TRANS_TX_READY) { - uartPort_t *s = (uartPort_t*)jetiExBusPort; - if (uartTotalTxBytesFree(jetiExBusPort) == (s->port.txBufferSize - 1)) { // workaround for 'isUartTransmitBufferEmpty()' + if (jetiExBusTransceiveState == EXBUS_TRANS_IS_TX_COMPLETED) { + if (isSerialTransmitBufferEmpty(jetiExBusPort)) { serialSetMode(jetiExBusPort, MODE_RX); jetiExBusTransceiveState = EXBUS_TRANS_RX; jetiExBusRequestState = EXBUS_STATE_ZERO; @@ -566,29 +583,26 @@ void sendJetiExBusTelemetry(uint8_t packetID) static uint8_t sensorDescriptionCounter = 0; static uint8_t sensorValueCounter = 1; static uint8_t requestLoop = 0; - + uint8_t *jetiExTelemetryFrame = &jetiExBusTelemetryFrame[EXBUS_HEADER_DATA]; if (requestLoop == 100){ //every nth request send the name of a value if (sensorDescriptionCounter == JETI_EX_SENSOR_COUNT ) sensorDescriptionCounter = 0; - createExTelemetrieTextMessage(jetiExTelemetry, sensorDescriptionCounter, &jetiExSensors[sensorDescriptionCounter]); - createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetry, packetID); + createExTelemetrieTextMessage(jetiExTelemetryFrame, sensorDescriptionCounter, &jetiExSensors[sensorDescriptionCounter]); + createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetryFrame, packetID); + requestLoop = 0; sensorDescriptionCounter++; - } else { - if (sensorValueCounter >= JETI_EX_SENSOR_COUNT) - sensorValueCounter = 1; - - sensorValueCounter = createExTelemetrieValueMessage(jetiExTelemetry, sensorValueCounter); - createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetry, packetID); + sensorValueCounter = createExTelemetrieValueMessage(jetiExTelemetryFrame, sensorValueCounter); + createExBusMessage(jetiExBusTelemetryFrame, jetiExTelemetryFrame, packetID); } for (uint8_t iCount = 0; iCount < jetiExBusTelemetryFrame[EXBUS_HEADER_MSG_LEN]; iCount++) { serialWrite(jetiExBusPort, jetiExBusTelemetryFrame[iCount]); } - jetiExBusTransceiveState = EXBUS_TRANS_TX_READY; + jetiExBusTransceiveState = EXBUS_TRANS_IS_TX_COMPLETED; requestLoop++; } From 3c01e78db6341659d5ebdb961da0fc9172bc2122 Mon Sep 17 00:00:00 2001 From: borisbstyle Date: Mon, 8 Feb 2016 23:25:58 +0100 Subject: [PATCH 5/5] Jeti Exbus telemetry set to 500hz --- src/main/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/main.c b/src/main/main.c index b4e02e8374..5a71368cc0 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -691,6 +691,8 @@ int main(void) { #endif #ifdef TELEMETRY setTaskEnabled(TASK_TELEMETRY, feature(FEATURE_TELEMETRY)); + // Reschedule telemetry to 500hz for Jeti Exbus + if (feature(FEATURE_TELEMETRY) || masterConfig.rxConfig.serialrx_provider == SERIALRX_JETIEXBUS) rescheduleTask(TASK_TELEMETRY, 2000); #endif #ifdef LED_STRIP setTaskEnabled(TASK_LEDSTRIP, feature(FEATURE_LED_STRIP));