642 lines
26 KiB
C++
642 lines
26 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program 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.
|
|
*/
|
|
|
|
#include "edgetx.h"
|
|
|
|
/*
|
|
* TXID + RXID are already skipped in MULTI module to save memory+transmission time, format from Multi is:
|
|
* AA or AC | TX_RSSI | sensor ...
|
|
*/
|
|
|
|
|
|
#define FLYSKY_TELEMETRY_LENGTH (2+7*4) // Should it be 2+7*6???
|
|
#define ALT_PRECISION 15
|
|
#define R_DIV_G_MUL_10_Q15 (uint64_t)9591506
|
|
#define INV_LOG2_E_Q1DOT31 (uint64_t)0x58b90bfc // Inverse log base 2 of e
|
|
#define PRESSURE_MASK 0x7FFFF
|
|
#define REMAP_CONST 0x1000 // Some part of OpenTX does not like sensor with id and instance 0, remap to 0x1000
|
|
|
|
struct FlySkySensor
|
|
{
|
|
const uint16_t type;
|
|
const TelemetryUnit unit;
|
|
const uint8_t precision;
|
|
const char * name;
|
|
};
|
|
|
|
// telemetry sensors type
|
|
enum
|
|
{
|
|
SENSOR_TYPE_RX_VOL= 0x00 | REMAP_CONST, // RX supply voltage, remapped
|
|
SENSOR_TYPE_TEMPERATURE = 0x01, // Temperature
|
|
SENSOR_TYPE_MOT = 0x02, // RPM
|
|
SENSOR_TYPE_EXT_VOL = 0x03, // Sensor voltage
|
|
SENSOR_TYPE_BVD = 0x103, // built-in voltage measurement of the receiver (the highest bit of ID is 1), which distinguishes independent voltage sensors.
|
|
SENSOR_TYPE_GYROSCOPE_1_AXIS = 0x04, // signed short in 0.1 degrees per second, 0x8000 if unknown
|
|
SENSOR_TYPE_GPS = 0x40, // GPS
|
|
SENSOR_TYPE_PRES = 0x41, // Pressure
|
|
SENSOR_TYPE_ALT = 0x1041, // virtual
|
|
|
|
SENSOR_TYPE_RF_MODULE = 0x56, // Ext flysky rf module sensor(voltage and temperature)
|
|
SENSOR_TYPE_RF_MODULE_TEMP = 0x1056, // virtual
|
|
SENSOR_TYPE_RF_MODULE_VOL = 0x2056, // virtual
|
|
SENSOR_TYPE_RF_MODULE_POWER = 0x3056, // virtual
|
|
// SENSOR_TYPE_RF_MODULE_RAW = 0x4056, // virtual
|
|
|
|
SENSOR_TYPE_TX_V = 0x7F, // TX Voltage
|
|
|
|
SENSOR_TYPE_ANALOG_SERVO =0xF0, // IBUS2 device
|
|
SENSOR_TYPE_DIGITAL_SERVO =0xF1, // IBUS2 device
|
|
|
|
SENSOR_TYPE_RX_SNR = 0xFA, // SNR
|
|
SENSOR_TYPE_RX_NOISE = 0xFB, // Noise
|
|
SENSOR_TYPE_RX_RSSI = 0xFC, // RSSI
|
|
SENSOR_TYPE_RX_ERR_RATE = 0xFE, // Error rate
|
|
SENSOR_TYPE_SIGNAL_STRENGTH = 0xFE, // Error rate
|
|
|
|
SENSOR_TYPE_END = 0xFF,
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
AFHDS2A_ID_BAT_CURR = 0x05, // battery current A * 100
|
|
AFHDS2A_ID_FUEL = 0x06, // remaining battery percentage / mah drawn otherwise or fuel level no unit!
|
|
AFHDS2A_ID_RPM = 0x07, // throttle value / battery capacity
|
|
AFHDS2A_ID_CMP_HEAD = 0x08, // Heading 0..360 deg, 0=north 2bytes
|
|
AFHDS2A_ID_CLIMB_RATE = 0x09, // 2 bytes m/s *100 signed
|
|
AFHDS2A_ID_COG = 0x0A, // 2 bytes Course over ground(NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. unknown max uint
|
|
AFHDS2A_ID_GPS_STATUS = 0x0B, // 2 bytes
|
|
AFHDS2A_ID_ACC_X = 0x0C, // 2 bytes m/s *100 signed
|
|
AFHDS2A_ID_ACC_Y = 0x0D, // 2 bytes m/s *100 signed
|
|
AFHDS2A_ID_ACC_Z = 0x0E, // 2 bytes m/s *100 signed
|
|
AFHDS2A_ID_ROLL = 0x0F, // 2 bytes deg *100 signed
|
|
AFHDS2A_ID_PITCH = 0x10, // 2 bytes deg *100 signed
|
|
AFHDS2A_ID_YAW = 0x11, // 2 bytes deg *100 signed
|
|
AFHDS2A_ID_VERTICAL_SPEED = 0x12, // 2 bytes m/s *100 signed
|
|
AFHDS2A_ID_GROUND_SPEED = 0x13, // 2 bytes m/s *100 different unit than build-in sensor
|
|
AFHDS2A_ID_GPS_DIST = 0x14, // 2 bytes distance from home m unsigned
|
|
AFHDS2A_ID_ARMED = 0x15, // 2 bytes
|
|
AFHDS2A_ID_FLIGHT_MODE = 0x16, // 2 bytes
|
|
|
|
AFHDS2A_ID_ODO1 = 0x7C, // Odometer1
|
|
AFHDS2A_ID_ODO2 = 0x7D, // Odometer2
|
|
AFHDS2A_ID_SPE = 0x7E, // Speed 2 bytes km/h
|
|
|
|
AFHDS2A_ID_GPS_LAT = 0x80, // 4bytes signed WGS84 in degrees * 1E7
|
|
AFHDS2A_ID_GPS_LON = 0x81, // 4bytes signed WGS84 in degrees * 1E7
|
|
AFHDS2A_ID_GPS_ALT = 0x82, // 4bytes signed!!! GPS alt m*100
|
|
|
|
AFHDS2A_ID_ALT = 0x83, // 4bytes signed!!! Alt m*100
|
|
|
|
AFHDS2A_ID_RX_SIG_AFHDS3 = 0xF7, // SIG
|
|
AFHDS2A_ID_RX_SNR_AFHDS3 = 0xF8, // SNR
|
|
AFHDS2A_ID_ALT_FLYSKY = 0xF9, // Altitude 2 bytes signed in m - used in FlySky native TX
|
|
|
|
// AC type telemetry with multiple values in one packet
|
|
AFHDS2A_ID_GPS_FULL = 0xFD,
|
|
AFHDS2A_ID_VOLT_FULL = 0xF0,
|
|
AFHDS2A_ID_ACC_FULL = 0xEF,
|
|
AFHDS2A_ID_TX_RSSI = 0x200, // Pseudo id outside 1 byte range of FlySky sensors
|
|
};
|
|
|
|
// telemetry sensors ID
|
|
enum
|
|
{
|
|
AFHDS2A_ID_VOLTAGE = 0x00, // Internal Voltage
|
|
AFHDS2A_ID_TEMPERATURE = 0x01, // Temperature
|
|
AFHDS2A_ID_MOT = 0x02, // RPM
|
|
AFHDS2A_ID_EXTV = 0x03, // External Voltage
|
|
AFHDS2A_ID_CELL_VOLTAGE = 0x04, // Avg Cell voltage
|
|
|
|
AFHDS3_FRM_TEMP = 0x57, //virtual
|
|
AFHDS3_FRM_EXT_V = 0x58, //virtual
|
|
|
|
AFHDS2A_ID_TX_V = 0x7F, // TX Voltage
|
|
|
|
AFHDS2A_ID_S84 = 0x84,
|
|
AFHDS2A_ID_S85 = 0x85,
|
|
AFHDS2A_ID_S86 = 0x86,
|
|
AFHDS2A_ID_S87 = 0x87,
|
|
AFHDS2A_ID_S88 = 0x88,
|
|
AFHDS2A_ID_S89 = 0x89,
|
|
AFHDS2A_ID_S8a = 0x8A,
|
|
|
|
AFHDS2A_ID_RX_SNR = 0xFA, // SNR
|
|
AFHDS2A_ID_RX_NOISE = 0xFB, // Noise
|
|
AFHDS2A_ID_RX_RSSI = 0xFC, // RSSI
|
|
AFHDS2A_ID_RX_ERR_RATE = 0xFE, // Error rate
|
|
AFHDS2A_ID_END = 0xFF,
|
|
};
|
|
|
|
// clang-format off
|
|
#define FS(type,name,unit,precision) {type,unit,precision,name}
|
|
|
|
const FlySkySensor flySkySensors[] = {
|
|
// flysky start
|
|
FS( SENSOR_TYPE_RX_VOL, STR_SENSOR_A1, UNIT_VOLTS, 2 ), // RX Voltage (remapped, really 0x0)
|
|
FS( SENSOR_TYPE_TEMPERATURE, STR_SENSOR_TEMP1, UNIT_CELSIUS, 1 ), // Temperature
|
|
FS( SENSOR_TYPE_MOT, STR_SENSOR_RPM, UNIT_RAW, 0 ), // RPM
|
|
FS( SENSOR_TYPE_EXT_VOL, STR_SENSOR_A3, UNIT_VOLTS, 2 ), // External voltage
|
|
FS( SENSOR_TYPE_BVD, "BVD", UNIT_VOLTS, 2 ), // BVD
|
|
FS( SENSOR_TYPE_GYROSCOPE_1_AXIS, STR_SENSOR_CELLS, UNIT_DEGREE, 1 ), //
|
|
FS( SENSOR_TYPE_PRES, STR_SENSOR_PRES, UNIT_RAW, 2 ), // 4 bytes In fact Temperature + Pressure -> Altitude
|
|
FS( SENSOR_TYPE_ALT, STR_SENSOR_ALT, UNIT_METERS, 2 ),
|
|
FS( SENSOR_TYPE_RF_MODULE_TEMP, STR_SENSOR_TEMP2, UNIT_CELSIUS, 0 ), // 1 bytes temperature
|
|
FS( SENSOR_TYPE_RF_MODULE_VOL, STR_SENSOR_TXV, UNIT_VOLTS, 2 ), // 2 bytes voltage
|
|
FS( SENSOR_TYPE_RF_MODULE_POWER, STR_SENSOR_TX_POWER, UNIT_DBM, 0 ), // 2 bytes DBM
|
|
// FS( SENSOR_TYPE_RF_MODULE_RAW, STR_SENSOR_TX_POWER, UNIT_RAW, 0 ), // 2 bytes DBM
|
|
FS( SENSOR_TYPE_TX_V, STR_SENSOR_TXV, UNIT_VOLTS, 2 ), // TX Voltage
|
|
FS( SENSOR_TYPE_RX_SNR, STR_SENSOR_RX_SNR, UNIT_DB, 0 ), // RX SNR
|
|
FS( SENSOR_TYPE_RX_NOISE, STR_SENSOR_RX_NOISE, UNIT_DBM, 0 ), // RX Noise
|
|
FS( SENSOR_TYPE_RX_RSSI, STR_SENSOR_RSSI, UNIT_DBM, 0 ), // RX RSSI (0xfc)
|
|
FS( SENSOR_TYPE_RX_ERR_RATE, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0 ), // RX error rate
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
FS( AFHDS2A_ID_BAT_CURR, STR_SENSOR_CURR, UNIT_AMPS, 2 ), // battery current A * 100
|
|
FS( AFHDS2A_ID_FUEL, STR_SENSOR_CAPACITY, UNIT_RAW, 0 ), // remaining battery percentage / mah drawn otherwise or fuel level no unit!
|
|
FS( AFHDS2A_ID_RPM, STR_SENSOR_RPM, UNIT_RAW, 0 ), // throttle value / battery capacity
|
|
FS( AFHDS2A_ID_CMP_HEAD, STR_SENSOR_HDG, UNIT_DEGREE, 0 ), // Heading 0..360 deg, 0=north 2bytes
|
|
FS( AFHDS2A_ID_CLIMB_RATE, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100
|
|
FS( AFHDS2A_ID_COG, STR_SENSOR_HDG, UNIT_DEGREE, 2 ), // 2 bytes Course over ground(NOT heading, but direction of movement) in degrees * 100, 0.0..359.99 degrees. unknown max uint
|
|
FS( AFHDS2A_ID_GPS_STATUS, STR_SENSOR_SATELLITES, UNIT_RAW, 0 ), // 2 bytes
|
|
FS( AFHDS2A_ID_ACC_X, STR_SENSOR_ACCX, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 signed
|
|
FS( AFHDS2A_ID_ACC_Y, STR_SENSOR_ACCY, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 signed
|
|
FS( AFHDS2A_ID_ACC_Z, STR_SENSOR_ACCZ, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 signed
|
|
FS( AFHDS2A_ID_ROLL, STR_SENSOR_ROLL, UNIT_DEGREE, 2 ), // 2 bytes deg *100 signed
|
|
FS( AFHDS2A_ID_PITCH, STR_SENSOR_PITCH, UNIT_DEGREE, 2 ), // 2 bytes deg *100 signed
|
|
FS( AFHDS2A_ID_YAW, STR_SENSOR_YAW, UNIT_DEGREE, 2 ), // 2 bytes deg *100 signed
|
|
FS( AFHDS2A_ID_VERTICAL_SPEED, STR_SENSOR_VSPD, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100
|
|
FS( AFHDS2A_ID_GROUND_SPEED, STR_SENSOR_GSPD, UNIT_METERS_PER_SECOND, 2 ), // 2 bytes m/s *100 different unit than build-in sensor
|
|
FS( AFHDS2A_ID_GPS_DIST, STR_SENSOR_DIST, UNIT_METERS, 0 ), // 2 bytes dist from home m unsigned
|
|
FS( AFHDS2A_ID_ARMED, STR_SENSOR_ARM, UNIT_RAW, 0 ), // 2 bytes
|
|
FS( AFHDS2A_ID_FLIGHT_MODE, STR_SENSOR_FLIGHT_MODE, UNIT_RAW, 0 ), // 2 bytes index
|
|
FS( SENSOR_TYPE_PRES | 0x100, STR_SENSOR_TEMP2, UNIT_CELSIUS, 1 ), // 2 bytes Temperature
|
|
FS( AFHDS2A_ID_ODO1, STR_SENSOR_ODO1, UNIT_METERS, 2 ), // 2 bytes Odometer1 -- some magic with 330 needed
|
|
FS( AFHDS2A_ID_ODO2, STR_SENSOR_ODO2, UNIT_METERS, 2 ), // 2 bytes Odometer2 -- some magic with 330 needed
|
|
FS( AFHDS2A_ID_SPE, STR_SENSOR_ASPD, UNIT_KMH, 2 ), // 2 bytes Speed km/h -- some magic with 330 needed
|
|
FS( AFHDS2A_ID_GPS_LAT, STR_SENSOR_GPS, UNIT_GPS, 0 ), // 4 bytes signed WGS84 in degrees * 1E7
|
|
//FS( AFHDS2A_ID_GPS_LON, STR_SENSOR_GPS, UNIT_GPS, 0 ), // 4 bytes signed WGS84 in degrees * 1E7
|
|
FS( AFHDS2A_ID_GPS_ALT, STR_SENSOR_GPSALT, UNIT_METERS, 2 ), // 4 bytes signed GPS alt m*100
|
|
FS( AFHDS2A_ID_ALT, STR_SENSOR_ALT, UNIT_METERS, 2 ), // 4 bytes signed Alt m*100
|
|
FS( AFHDS2A_ID_RX_SIG_AFHDS3, STR_SENSOR_RX_QUALITY, UNIT_PERCENT, 0 ), // RX error rate
|
|
FS( AFHDS2A_ID_RX_SNR_AFHDS3, STR_SENSOR_RX_SNR, UNIT_DB, 1 ), // RX SNR
|
|
FS( AFHDS2A_ID_TX_RSSI, STR_SENSOR_TX_RSSI, UNIT_DBM, 0 ), // Pseudo sensor for TRSSI
|
|
|
|
FS( 0x00, NULL, UNIT_RAW, 0 ), // sentinel
|
|
};
|
|
// clang-format on
|
|
|
|
int32_t getALT(uint32_t value);
|
|
inline int setFlyskyTelemetryValue( int16_t type, uint8_t instance, int32_t value, uint32_t unit, uint32_t prec)
|
|
{
|
|
return setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, type, 0, instance, value, unit, prec );
|
|
}
|
|
|
|
void processFlySkyAFHDS3Sensor(const uint8_t * packet, uint8_t len )
|
|
{
|
|
uint16_t type = (packet[0] << 8) | packet[1];
|
|
type = type ? type : SENSOR_TYPE_RX_VOL; // Remapped
|
|
uint8_t id = packet[2];
|
|
int32_t value=0;
|
|
|
|
if(len == 1)
|
|
{
|
|
value = packet[3];
|
|
}
|
|
else if (len == 2)
|
|
{
|
|
value = (packet[4] << 8) | packet[3];
|
|
}
|
|
else if(len == 4)
|
|
{
|
|
value = (packet[6] << 24) | (packet[5] << 16) | (packet[4] << 8) | packet[3];
|
|
}
|
|
else
|
|
{
|
|
if( SENSOR_TYPE_GPS == type )
|
|
{
|
|
//INRM301 does not support GPS temporarily.
|
|
return;
|
|
}
|
|
else if( SENSOR_TYPE_RF_MODULE == type )
|
|
{
|
|
uint8_t data1[] = { (uint8_t)(SENSOR_TYPE_RF_MODULE_TEMP>>8), (uint8_t)SENSOR_TYPE_RF_MODULE_TEMP, id, packet[3] };
|
|
uint8_t data2[] = { (uint8_t)(SENSOR_TYPE_RF_MODULE_VOL>>8), (uint8_t)SENSOR_TYPE_RF_MODULE_VOL, id, packet[4], packet[5] };
|
|
uint8_t data3[] = { (uint8_t)(SENSOR_TYPE_RF_MODULE_POWER>>8), (uint8_t)SENSOR_TYPE_RF_MODULE_POWER, id, packet[8], packet[9] };
|
|
// uint8_t data4[] = { (uint8_t)(SENSOR_TYPE_RF_MODULE_RAW>>8), (uint8_t)SENSOR_TYPE_RF_MODULE_RAW, id, packet[6] & 0x07};
|
|
|
|
processFlySkyAFHDS3Sensor(data1, 1 );
|
|
processFlySkyAFHDS3Sensor(data2, 2 );
|
|
processFlySkyAFHDS3Sensor(data3, 2 );
|
|
// processFlySkyAFHDS3Sensor(data4, 1 );
|
|
return;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
if (SENSOR_TYPE_RX_NOISE == type || SENSOR_TYPE_RX_RSSI == type)
|
|
{
|
|
value = -value;
|
|
}
|
|
|
|
if ( (SENSOR_TYPE_EXT_VOL == type) )
|
|
{
|
|
if ( id&0x80 )
|
|
{
|
|
type = SENSOR_TYPE_BVD;
|
|
}
|
|
}
|
|
else if(SENSOR_TYPE_RX_RSSI == type || SENSOR_TYPE_RX_NOISE == type || SENSOR_TYPE_RX_SNR == type || SENSOR_TYPE_RF_MODULE_POWER == type)
|
|
{
|
|
if( value>=0 )
|
|
value = (value+2)/4;
|
|
else
|
|
value = (value-2)/4;
|
|
}
|
|
else if (SENSOR_TYPE_RX_ERR_RATE == type)
|
|
{
|
|
telemetryData.rssi.set( value );
|
|
if (value > 0) telemetryStreaming = TELEMETRY_TIMEOUT10ms;
|
|
}
|
|
else if (SENSOR_TYPE_PRES == type)
|
|
{
|
|
int32_t alt = getALT(value);
|
|
int16_t temp = (value >> 19);
|
|
|
|
uint8_t data1[] = { (uint8_t)(SENSOR_TYPE_ALT>>8), (uint8_t)(SENSOR_TYPE_ALT&0xff), id, (uint8_t)alt, (uint8_t)(alt>>8), (uint8_t)(alt>>16), (uint8_t)(alt>>24) };
|
|
uint8_t data2[] = { (uint8_t)(SENSOR_TYPE_TEMPERATURE>>8), (uint8_t)(SENSOR_TYPE_TEMPERATURE&0xff), id, (uint8_t)temp, (uint8_t)(temp>>8) };
|
|
processFlySkyAFHDS3Sensor(data1, 4 );
|
|
processFlySkyAFHDS3Sensor(data2, 2 );
|
|
value &= PRESSURE_MASK;
|
|
}
|
|
|
|
if(SENSOR_TYPE_TEMPERATURE == type)
|
|
{
|
|
value -= 400; // Temperature sensors have 40 degree offset
|
|
}
|
|
|
|
for (const FlySkySensor * sensor = flySkySensors; sensor->type; sensor++)
|
|
{
|
|
if (sensor->type != type) continue;
|
|
|
|
if (sensor->unit == UNIT_VOLTS) value = (int16_t) value; // Voltage types are unsigned 16bit integers
|
|
|
|
setFlyskyTelemetryValue(type, id, value, sensor->unit, sensor->precision);
|
|
return;
|
|
}
|
|
//unknown
|
|
setFlyskyTelemetryValue(type, id, value, UNIT_RAW, 0);
|
|
}
|
|
|
|
|
|
void processFlySkySensor(const uint8_t * packet, uint8_t type)
|
|
{
|
|
uint8_t buffer[8];
|
|
uint16_t id = packet[0];
|
|
const uint8_t instance = packet[1];
|
|
int32_t value;
|
|
|
|
//Load most likely value
|
|
if (type == 0xAA)
|
|
value = (packet[3] << 8) | packet[2];
|
|
else
|
|
value = (packet[6] << 24) | (packet[5] << 16) | (packet[4] << 8) | packet[3];
|
|
|
|
id = id ? id : SENSOR_TYPE_RX_VOL; // Remapped
|
|
|
|
if (id == AFHDS2A_ID_RX_NOISE || id == AFHDS2A_ID_RX_RSSI) {
|
|
value = 135 - value;
|
|
}
|
|
else if (id == AFHDS2A_ID_RX_ERR_RATE) {
|
|
value = 100 - value;
|
|
telemetryData.rssi.set(value);
|
|
if (value > 0) telemetryStreaming = TELEMETRY_TIMEOUT10ms;
|
|
}
|
|
else if(id == AFHDS2A_ID_RX_SIG_AFHDS3) {
|
|
telemetryData.rssi.set(value);
|
|
if(value>0) telemetryStreaming = TELEMETRY_TIMEOUT10ms;
|
|
}
|
|
else if (id == SENSOR_TYPE_PRES && value) {
|
|
// Extract temperature to a new sensor
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, id | 0x100, 0, instance, ((value >> 19) - 400), UNIT_CELSIUS, 1);
|
|
// Extract alt to a new sensor
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, AFHDS2A_ID_ALT, 0, instance, getALT(value), UNIT_METERS, 2);
|
|
value &= PRESSURE_MASK;
|
|
}
|
|
else if ((id >= AFHDS2A_ID_ACC_X && id <= AFHDS2A_ID_VERTICAL_SPEED) || id == AFHDS2A_ID_CLIMB_RATE || id == AFHDS2A_ID_ALT_FLYSKY) {
|
|
value = (int16_t) value; // Signed value
|
|
}
|
|
else if (id == AFHDS2A_ID_GPS_STATUS) {
|
|
value = value >> 8;
|
|
}
|
|
else if (id == AFHDS2A_ID_GPS_FULL) {
|
|
//(AC FRAME)[ID][inst][size][fix][sats][LAT]x4[LON]x4[ALT]x4
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, AFHDS2A_ID_GPS_STATUS, 0, instance, packet[4], UNIT_RAW, 0);
|
|
|
|
for (uint8_t sensorID = AFHDS2A_ID_GPS_LAT; sensorID <= AFHDS2A_ID_GPS_ALT; sensorID++) {
|
|
int index = 5 + (sensorID - AFHDS2A_ID_GPS_LAT) * 4;
|
|
buffer[0] = sensorID;
|
|
buffer[1] = instance;
|
|
buffer[2] = 4;
|
|
memcpy(buffer + 3, packet + index, 4);
|
|
processFlySkySensor(buffer, 0xAC);
|
|
}
|
|
|
|
return;
|
|
} else if (id == AFHDS2A_ID_GPS_LAT) {
|
|
uint8_t instance2 = 0; // Assume one instance, RX would only have one GPS
|
|
value = value / 10;
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, AFHDS2A_ID_GPS_LAT, 0,
|
|
instance2, value, UNIT_GPS_LATITUDE, 0);
|
|
return;
|
|
} else if (id == AFHDS2A_ID_GPS_LON) { // Remapped to single GPS sensor:
|
|
// AFHDS2A_ID_GPS_LAT
|
|
uint8_t instance2 = 0;
|
|
value = value / 10;
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, AFHDS2A_ID_GPS_LAT, 0,
|
|
instance2, value, UNIT_GPS_LONGITUDE, 0);
|
|
return;
|
|
} else if (id == AFHDS2A_ID_VOLT_FULL) {
|
|
//(AC FRAME)[ID][inst][size][ACC_X]x2[ACC_Y]x2[ACC_Z]x2[ROLL]x2[PITCH]x2[YAW]x2
|
|
for (uint8_t sensorID = AFHDS2A_ID_EXTV; sensorID <= AFHDS2A_ID_RPM; sensorID++) {
|
|
int index = 3 + (sensorID - AFHDS2A_ID_EXTV) * 2;
|
|
buffer[0] = sensorID;
|
|
buffer[1] = instance;
|
|
buffer[2] = packet[index];
|
|
buffer[3] = packet[index + 1];
|
|
processFlySkySensor(buffer, 0xAA);
|
|
}
|
|
return;
|
|
} else if (id == AFHDS2A_ID_ACC_FULL) {
|
|
//(AC FRAME)[ID][inst][size]
|
|
for (uint8_t sensorID = AFHDS2A_ID_ACC_X; sensorID <= AFHDS2A_ID_YAW; sensorID++) {
|
|
int index = 3 + (sensorID - AFHDS2A_ID_ACC_X) * 2;
|
|
buffer[0] = sensorID;
|
|
buffer[1] = instance;
|
|
buffer[2] = packet[index];
|
|
buffer[3] = packet[index + 1];
|
|
processFlySkySensor(buffer, 0xAA);
|
|
}
|
|
return;
|
|
}
|
|
for (const FlySkySensor * sensor = flySkySensors; sensor->type; sensor++) {
|
|
if (sensor->type != id) continue;
|
|
if (sensor->unit == UNIT_CELSIUS) value -= 400; // Temperature sensors have 40 degree offset
|
|
else if (sensor->unit == UNIT_VOLTS) value = (int16_t) value; // Voltage types are unsigned 16bit integers
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, id, 0, instance, value, sensor->unit, sensor->precision);
|
|
return;
|
|
}
|
|
//unknown
|
|
setTelemetryValue(PROTOCOL_TELEMETRY_FLYSKY_IBUS, id, 0, instance, value, UNIT_RAW, 0);
|
|
}
|
|
|
|
void processFlySkyPacket(const uint8_t * packet)
|
|
{
|
|
// Set TX RSSI Value, reverse MULTIs scaling
|
|
setFlyskyTelemetryValue(AFHDS2A_ID_TX_RSSI, 0, packet[0], UNIT_RAW, 0);
|
|
|
|
const uint8_t * buffer = packet + 1;
|
|
int sensor = 0;
|
|
while (sensor++ < 7) {
|
|
if (*buffer == SENSOR_TYPE_END) break;
|
|
processFlySkySensor(buffer, 0xAA);
|
|
buffer += 4;
|
|
}
|
|
}
|
|
|
|
void processFlySkyPacketAC(const uint8_t * packet)
|
|
{
|
|
// Set TX RSSI Value, reverse MULTIs scaling
|
|
setFlyskyTelemetryValue(AFHDS2A_ID_TX_RSSI, 0, packet[0], UNIT_RAW, 0);
|
|
const uint8_t * buffer = packet + 1;
|
|
while (buffer - packet < 26) //28 + 1(multi TX rssi) - 3(ac header)
|
|
{
|
|
if (*buffer == SENSOR_TYPE_END) break;
|
|
uint8_t size = buffer[2];
|
|
processFlySkySensor(buffer, 0xAC);
|
|
buffer += size + 3;
|
|
}
|
|
}
|
|
|
|
void processFlySkyTelemetryData(uint8_t data, uint8_t * rxBuffer, uint8_t &rxBufferCount)
|
|
{
|
|
if (rxBufferCount == 0)
|
|
return;
|
|
|
|
if (data == 2 || data == 4) {
|
|
TRACE("[IBUS] Packet 0x%02X", data);
|
|
}
|
|
else {
|
|
TRACE("[IBUS] invalid start byte 0x%02X", data);
|
|
rxBufferCount = 0;
|
|
return;
|
|
}
|
|
|
|
if (rxBufferCount < TELEMETRY_RX_PACKET_SIZE) {
|
|
rxBuffer[rxBufferCount++] = data;
|
|
}
|
|
else {
|
|
TRACE("[IBUS] array size %d error", rxBufferCount);
|
|
rxBufferCount = 0;
|
|
}
|
|
|
|
if (rxBufferCount >= FLYSKY_TELEMETRY_LENGTH) {
|
|
// debug print the content of the packets
|
|
#if 0
|
|
debugPrintf(", rssi 0x%02X: ", rxBuffer[1]);
|
|
for (int i=0; i<7; i++) {
|
|
debugPrintf("[%02X %02X %02X%02X] ", rxBuffer[i*4+2], rxBuffer[i*4 + 3],
|
|
rxBuffer[i*4 + 4], rxBuffer[i*4 + 5]);
|
|
}
|
|
debugPrintf(CRLF);
|
|
#endif
|
|
if (data == 0xAA) processFlySkyPacket(rxBuffer + 1);
|
|
else if (data == 0xAC) processFlySkyPacketAC(rxBuffer + 1);
|
|
rxBufferCount = 0;
|
|
}
|
|
}
|
|
|
|
const FlySkySensor * getFlySkySensor(uint16_t id)
|
|
{
|
|
for (const FlySkySensor * sensor = flySkySensors; sensor->type; sensor++) {
|
|
if (id == sensor->type)
|
|
return sensor;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void flySkySetDefault(int index, uint16_t id, uint8_t subId, uint8_t instance)
|
|
{
|
|
TelemetrySensor &telemetrySensor = g_model.telemetrySensors[index];
|
|
telemetrySensor.id = id;
|
|
telemetrySensor.subId = subId;
|
|
telemetrySensor.instance = instance;
|
|
|
|
const FlySkySensor * sensor = getFlySkySensor(id);
|
|
if (sensor) {
|
|
TelemetryUnit unit = sensor->unit;
|
|
uint8_t prec = min<uint8_t>(2, sensor->precision);
|
|
telemetrySensor.init(sensor->name, unit, prec);
|
|
|
|
if (unit == UNIT_RPMS) {
|
|
telemetrySensor.custom.ratio = 1;
|
|
telemetrySensor.custom.offset = 1;
|
|
}
|
|
}
|
|
else {
|
|
telemetrySensor.init(id);
|
|
}
|
|
|
|
storageDirty(EE_MODEL);
|
|
}
|
|
|
|
uint16_t ibusTempToK(int16_t tempertureIbus)
|
|
{
|
|
return (uint16_t) (tempertureIbus - 400) + 2731;
|
|
}
|
|
|
|
int32_t log2fix(uint32_t x)
|
|
{
|
|
int32_t b = 1U << (ALT_PRECISION - 1);
|
|
int32_t y = 0;
|
|
while (x < 1U << ALT_PRECISION) {
|
|
x <<= 1;
|
|
y -= 1U << ALT_PRECISION;
|
|
}
|
|
|
|
while (x >= 2U << ALT_PRECISION) {
|
|
x >>= 1;
|
|
y += 1U << ALT_PRECISION;
|
|
}
|
|
|
|
uint64_t z = x;
|
|
for (size_t i = 0; i < ALT_PRECISION; i++) {
|
|
z = (z * z) >> ALT_PRECISION;
|
|
if (z >= 2U << ALT_PRECISION) {
|
|
z >>= 1;
|
|
y += b;
|
|
}
|
|
b >>= 1;
|
|
}
|
|
return y;
|
|
}
|
|
|
|
#if 0
|
|
int32_t getALT(uint32_t value)
|
|
{
|
|
uint32_t pressurePa = value & PRESSURE_MASK;
|
|
if (pressurePa == 0) return 0;
|
|
uint16_t temperatureK = ibusTempToK((uint16_t) (value >> 19));
|
|
static uint32_t initPressure = 0;
|
|
static uint16_t initTemperature = 0;
|
|
if (initPressure <= 0) // use current pressure for ground altitude -> 0
|
|
{
|
|
initPressure = pressurePa;
|
|
initTemperature = temperatureK;
|
|
}
|
|
int temperature = (initTemperature + temperatureK) >> 1; //div 2
|
|
bool tempNegative = temperature < 0;
|
|
if (tempNegative) temperature = temperature * -1;
|
|
uint64_t helper = R_DIV_G_MUL_10_Q15;
|
|
helper = helper * (uint64_t) temperature;
|
|
helper = helper >> ALT_PRECISION;
|
|
|
|
uint32_t po_to_p = (uint32_t)(initPressure << (ALT_PRECISION - 1));
|
|
po_to_p = po_to_p / pressurePa;
|
|
//shift missing bit
|
|
po_to_p = po_to_p << 1;
|
|
if (po_to_p == 0) return 0;
|
|
uint64_t t = log2fix(po_to_p) * INV_LOG2_E_Q1DOT31;
|
|
int32_t ln = t >> 31;
|
|
|
|
bool neg = ln < 0;
|
|
if (neg) ln = ln * -1;
|
|
helper = helper * (uint64_t) ln;
|
|
helper = helper >> ALT_PRECISION;
|
|
int result = (int) helper;
|
|
|
|
if (neg ^ tempNegative) result = result * -1;
|
|
return result;
|
|
}
|
|
#else
|
|
/*==================================================================================================
|
|
table:
|
|
Function:
|
|
==================================================================================================*/
|
|
const int16_t tAltitude[225]=
|
|
{ // In half meter unit
|
|
20558, 20357, 20158, 19962, 19768, 19576, 19387, 19200, 19015, 18831, 18650, 18471, 18294, 18119, 17946, 17774,
|
|
17604, 17436, 17269, 17105, 16941, 16780, 16619, 16461, 16304, 16148, 15993, 15841, 15689, 15539, 15390, 15242,
|
|
15096, 14950, 14806, 14664, 14522, 14381, 14242, 14104, 13966, 13830, 13695, 13561, 13428, 13296, 13165, 13035,
|
|
12906, 12777, 12650, 12524, 12398, 12273, 12150, 12027, 11904, 11783, 11663, 11543, 11424, 11306, 11189, 11072,
|
|
10956, 10841, 10726, 10613, 10500, 10387, 10276, 10165, 10054, 9945, 9836, 9727, 9620, 9512, 9406, 9300,
|
|
9195, 9090, 8986, 8882, 8779, 8677, 8575, 8474, 8373, 8273, 8173, 8074, 7975, 7877, 7779, 7682,
|
|
7585, 7489, 7394, 7298, 7204, 7109, 7015, 6922, 6829, 6737, 6645, 6553, 6462, 6371, 6281, 6191,
|
|
6102, 6012, 5924, 5836, 5748, 5660, 5573, 5487, 5400, 5314, 5229, 5144, 5059, 4974, 4890, 4807,
|
|
4723, 4640, 4557, 4475, 4393, 4312, 4230, 4149, 4069, 3988, 3908, 3829, 3749, 3670, 3591, 3513,
|
|
3435, 3357, 3280, 3202, 3125, 3049, 2972, 2896, 2821, 2745, 2670, 2595, 2520, 2446, 2372, 2298,
|
|
2224, 2151, 2078, 2005, 1933, 1861, 1789, 1717, 1645, 1574, 1503, 1432, 1362, 1292, 1222, 1152,
|
|
1082, 1013, 944, 875, 806, 738, 670, 602, 534, 467, 399, 332, 265, 199, 132, 66,
|
|
0, -66, -131, -197, -262, -327, -392, -456, -521, -585, -649, -713, -776, -840, -903, -966,
|
|
-1029,-1091, -1154, -1216, -1278, -1340, -1402, -1463, -1525, -1586, -1647, -1708, -1769, -1829, -1889, -1950,
|
|
-2010
|
|
};
|
|
/*==================================================================================================
|
|
Name:
|
|
Function:
|
|
Input:
|
|
Output:
|
|
==================================================================================================*/
|
|
int32_t getALT(uint32_t Pressure)//CalculateAltitude( uint32_t Pressure, uint32_t SeaLevelPressure )
|
|
{
|
|
uint32_t Index;
|
|
int32_t Altitude1;
|
|
int32_t Altitude2;
|
|
uint32_t Decimal;
|
|
uint64_t Ratio;
|
|
uint32_t SeaLevelPressure=101320;
|
|
Pressure = Pressure & PRESSURE_MASK;
|
|
Ratio = ( ( ( unsigned long long ) Pressure << 16 ) + ( SeaLevelPressure / 2 ) ) / SeaLevelPressure;
|
|
if( Ratio < ( ( 1 << 16 ) * 250 / 1000 ) )// 0.250 inclusive
|
|
{
|
|
Ratio = ( 1 << 16 ) * 250 / 1000;
|
|
}
|
|
else if( Ratio > ( 1 << 16 ) * 1125 / 1000 - 1 ) // 1.125 non-inclusive
|
|
{
|
|
Ratio = ( 1 << 16 ) * 1125 / 1000 - 1;
|
|
}
|
|
|
|
Ratio -= ( 1 << 16 ) * 250 / 1000; // from 0.000 (inclusive) to 0.875 (non-inclusive)
|
|
Index = Ratio >> 8;
|
|
Decimal = Ratio & ( ( 1 << 8 ) - 1 );
|
|
Altitude1 = tAltitude[Index];
|
|
Altitude2 = Altitude1 - tAltitude[Index + 1];
|
|
Altitude1 = Altitude1 - ( Altitude2 * Decimal + ( 1 << 7 ) ) / ( 1 << 8 );
|
|
Altitude1 *= 100;
|
|
if( Altitude1 >= 0 )
|
|
{
|
|
return( ( Altitude1 + 1 ) / 2 );
|
|
}
|
|
else
|
|
{
|
|
return( ( Altitude1 - 1 ) / 2 );
|
|
}
|
|
}
|
|
#endif |