mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-11-29 07:24:13 +01:00
674 lines
20 KiB
C
674 lines
20 KiB
C
/**
|
|
******************************************************************************
|
|
*
|
|
* @file frsky_packing.c
|
|
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017-2019
|
|
* Tau Labs, http://taulabs.org, Copyright (C) 2015
|
|
* @brief Packs UAVObjects into FrSKY Smart Port frames
|
|
*
|
|
* Since there is no public documentation of SmartPort protocol available,
|
|
* this was put together by studying OpenTx source code, reading
|
|
* tidbits of informations on the Internet and experimenting.
|
|
* @see https://github.com/opentx/opentx/tree/next/radio/src/telemetry
|
|
* @see https://code.google.com/p/telemetry-convert/wiki/FrSkySPortProtocol
|
|
* @see The GNU Public License (GPL) Version 3
|
|
*
|
|
*****************************************************************************/
|
|
/*
|
|
* This program 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.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "frsky_packing.h"
|
|
#include "frskysporttelemetrysettings.h"
|
|
#include "attitudestate.h"
|
|
#include "barosensor.h"
|
|
#include "positionstate.h"
|
|
#include "velocitystate.h"
|
|
#include "flightbatterystate.h"
|
|
#include "flightbatterysettings.h"
|
|
#include "gpstime.h"
|
|
#include "homelocation.h"
|
|
#include "accelstate.h"
|
|
#include "flightstatus.h"
|
|
#include "airspeedstate.h"
|
|
#include "nedaccel.h"
|
|
|
|
#define GRAVITY 9.805f // [m/s^2]
|
|
#define KNOTS2M_PER_SECOND 0.514444444f
|
|
|
|
|
|
/**
|
|
* Encode baro altitude value
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_altitude(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (!frsky->use_baro_sensor || (PositionStateHandle() == NULL)) {
|
|
return false;
|
|
}
|
|
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
// instead of encoding baro altitude directly, we will use
|
|
// more accurate estimation in PositionState UAVO
|
|
float down = 0;
|
|
PositionStateDownGet(&down);
|
|
int32_t alt = (int32_t)(-down * 100.0f);
|
|
*value = (uint32_t)alt;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode heading value
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_gps_course(__attribute__((unused)) struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (AttitudeStateHandle() == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
AttitudeStateData attitude;
|
|
AttitudeStateGet(&attitude);
|
|
float hdg = (attitude.Yaw >= 0) ? attitude.Yaw : (attitude.Yaw + 360.0f);
|
|
*value = (uint32_t)(hdg * 100.0f);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode vertical speed value
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_vario(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (!frsky->use_baro_sensor || VelocityStateHandle() == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
float down = 0;
|
|
VelocityStateDownGet(&down);
|
|
int32_t vspeed = (int32_t)(-down * 100.0f);
|
|
*value = (uint32_t)vspeed;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode battery current value
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_current(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (!frsky->use_current_sensor) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
float current = 0;
|
|
FlightBatteryStateCurrentGet(¤t);
|
|
int32_t current_frsky = (int32_t)(current * 10.0f);
|
|
*value = (uint32_t)current_frsky;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode battery cells voltage
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[], index of battery cell pair
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_cells(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
|
|
{
|
|
if ((frsky->batt_cell_count == 0) || (frsky->batt_cell_count - 1) < (int)(arg * 2)) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
float voltage = 0;
|
|
FlightBatteryStateVoltageGet(&voltage);
|
|
|
|
uint32_t cell_voltage = (uint32_t)((voltage * 500.0f) / frsky->batt_cell_count);
|
|
*value = ((cell_voltage & 0xfff) << 8) | ((arg * 2) & 0x0f) | ((frsky->batt_cell_count << 4) & 0xf0);
|
|
if (((int16_t)frsky->batt_cell_count - 1) >= (int)(arg * 2 + 1)) {
|
|
*value |= ((cell_voltage & 0xfff) << 20);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode GPS status as T1 value
|
|
* Right-most two digits means visible satellite count, left-most digit has following meaning:
|
|
* 1 - no GPS connected
|
|
* 2 - no fix
|
|
* 3 - 2D fix
|
|
* 4 - 3D fix
|
|
* 5 - 3D fix and HomeLocation is SET - should be safe for navigation
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value successfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_t1(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (GPSPositionSensorHandle() == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
uint8_t hl_set = HOMELOCATION_SET_FALSE;
|
|
|
|
if (HomeLocationHandle()) {
|
|
HomeLocationSetGet(&hl_set);
|
|
}
|
|
|
|
int32_t t1 = 0;
|
|
switch (frsky->gps_position.Status) {
|
|
case GPSPOSITIONSENSOR_STATUS_NOGPS:
|
|
t1 = 100;
|
|
break;
|
|
case GPSPOSITIONSENSOR_STATUS_NOFIX:
|
|
t1 = 200;
|
|
break;
|
|
case GPSPOSITIONSENSOR_STATUS_FIX2D:
|
|
t1 = 300;
|
|
break;
|
|
case GPSPOSITIONSENSOR_STATUS_FIX3D:
|
|
case GPSPOSITIONSENSOR_STATUS_FIX3DDGNSS:
|
|
if (hl_set == HOMELOCATION_SET_TRUE) {
|
|
t1 = 500;
|
|
} else {
|
|
t1 = 400;
|
|
}
|
|
break;
|
|
}
|
|
if (frsky->gps_position.Satellites > 0) {
|
|
t1 += frsky->gps_position.Satellites;
|
|
}
|
|
|
|
*value = (uint32_t)t1;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode GPS hDop and vDop as T2
|
|
* Bits 0-7 = hDop * 100, max 255 (hDop = 2.55)
|
|
* Bits 8-15 = vDop * 100, max 255 (vDop = 2.55)
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value successfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_t2(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (GPSPositionSensorHandle() == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
uint32_t hdop = (uint32_t)(frsky->gps_position.HDOP * 100.0f);
|
|
|
|
if (hdop > 255) {
|
|
hdop = 255;
|
|
}
|
|
|
|
uint32_t vdop = (uint32_t)(frsky->gps_position.VDOP * 100.0f);
|
|
|
|
if (vdop > 255) {
|
|
vdop = 255;
|
|
}
|
|
|
|
*value = 256 * vdop + hdop;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode consumed battery energy as fuel
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_fuel(__attribute__((unused)) struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (!frsky->use_current_sensor) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
uint32_t capacity = frsky->battery_settings.Capacity;
|
|
float consumed_mahs = 0;
|
|
FlightBatteryStateConsumedEnergyGet(&consumed_mahs);
|
|
|
|
float fuel = (uint32_t)(100.0f * (1.0f - consumed_mahs / capacity));
|
|
fuel = boundf(fuel, 0.0f, 100.0f);
|
|
*value = (uint32_t)fuel;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode configured values
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]; 0=X, 1=Y, 2=Z
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_acc(__attribute__((unused)) struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
|
|
{
|
|
uint8_t accelDataSettings;
|
|
|
|
FrSKYSPortTelemetrySettingsAccelDataGet(&accelDataSettings);
|
|
|
|
float acc = 0;
|
|
switch (accelDataSettings) {
|
|
case FRSKYSPORTTELEMETRYSETTINGS_ACCELDATA_ACCELS:
|
|
{
|
|
if (AccelStateHandle() == NULL) {
|
|
return false;
|
|
} else if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
switch (arg) {
|
|
case 0:
|
|
AccelStatexGet(&acc);
|
|
break;
|
|
case 1:
|
|
AccelStateyGet(&acc);
|
|
break;
|
|
case 2:
|
|
AccelStatezGet(&acc);
|
|
break;
|
|
}
|
|
|
|
acc /= GRAVITY;
|
|
acc *= 100.0f;
|
|
break;
|
|
}
|
|
|
|
case FRSKYSPORTTELEMETRYSETTINGS_ACCELDATA_NEDACCELS:
|
|
{
|
|
if (NedAccelHandle() == NULL) {
|
|
return false;
|
|
} else if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
switch (arg) {
|
|
case 0:
|
|
NedAccelNorthGet(&acc);
|
|
break;
|
|
case 1:
|
|
NedAccelEastGet(&acc);
|
|
break;
|
|
case 2:
|
|
NedAccelDownGet(&acc);
|
|
break;
|
|
}
|
|
|
|
acc /= GRAVITY;
|
|
acc *= 100.0f;
|
|
break;
|
|
}
|
|
|
|
case FRSKYSPORTTELEMETRYSETTINGS_ACCELDATA_NEDVELOCITY:
|
|
{
|
|
if (VelocityStateHandle() == NULL) {
|
|
return false;
|
|
} else if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
switch (arg) {
|
|
case 0:
|
|
VelocityStateNorthGet(&acc);
|
|
break;
|
|
case 1:
|
|
VelocityStateEastGet(&acc);
|
|
break;
|
|
case 2:
|
|
VelocityStateDownGet(&acc);
|
|
break;
|
|
}
|
|
|
|
acc *= 100.0f;
|
|
break;
|
|
}
|
|
|
|
case FRSKYSPORTTELEMETRYSETTINGS_ACCELDATA_ATTITUDEANGLES:
|
|
{
|
|
if (AttitudeStateHandle() == NULL) {
|
|
return false;
|
|
} else if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
switch (arg) {
|
|
case 0:
|
|
AttitudeStateRollGet(&acc);
|
|
break;
|
|
case 1:
|
|
AttitudeStatePitchGet(&acc);
|
|
break;
|
|
case 2:
|
|
AttitudeStateYawGet(&acc);
|
|
break;
|
|
}
|
|
|
|
acc *= 100.0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int32_t frsky_acc = (int32_t)acc;
|
|
*value = (uint32_t)frsky_acc;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode gps coordinates
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]; 0=lattitude, 1=longitude
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_gps_coord(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
|
|
{
|
|
if (GPSPositionSensorHandle() == NULL) {
|
|
return false;
|
|
}
|
|
if (frsky->gps_position.Status == GPSPOSITIONSENSOR_STATUS_NOFIX
|
|
|| frsky->gps_position.Status == GPSPOSITIONSENSOR_STATUS_NOGPS) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
uint32_t frsky_coord = 0;
|
|
int32_t coord = 0;
|
|
if (arg == 0) {
|
|
// lattitude
|
|
coord = frsky->gps_position.Latitude;
|
|
if (coord >= 0) {
|
|
frsky_coord = 0;
|
|
} else {
|
|
frsky_coord = 1 << 30;
|
|
}
|
|
} else {
|
|
// longitude
|
|
coord = frsky->gps_position.Longitude;
|
|
if (coord >= 0) {
|
|
frsky_coord = 2 << 30;
|
|
} else {
|
|
frsky_coord = 3 << 30;
|
|
}
|
|
}
|
|
coord = abs(coord);
|
|
frsky_coord |= (((uint64_t)coord * 6ull) / 100);
|
|
|
|
*value = frsky_coord;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode gps altitude
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_gps_alt(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (GPSPositionSensorHandle() == NULL) {
|
|
return false;
|
|
}
|
|
if (frsky->gps_position.Status != GPSPOSITIONSENSOR_STATUS_FIX3D) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
int32_t frsky_gps_alt = (int32_t)(frsky->gps_position.Altitude * 100.0f);
|
|
*value = (uint32_t)frsky_gps_alt;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode gps speed
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_gps_speed(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (GPSPositionSensorHandle() == NULL) {
|
|
return false;
|
|
}
|
|
if (frsky->gps_position.Status != GPSPOSITIONSENSOR_STATUS_FIX3D) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
int32_t frsky_speed = (int32_t)((frsky->gps_position.Groundspeed / KNOTS2M_PER_SECOND) * 1000);
|
|
*value = frsky_speed;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode GPS UTC time
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]; 0=date, 1=time
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_gps_time(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
|
|
{
|
|
if (GPSPositionSensorHandle() == NULL || GPSTimeHandle() == NULL) {
|
|
return false;
|
|
}
|
|
if (frsky->gps_position.Status != GPSPOSITIONSENSOR_STATUS_FIX3D) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
GPSTimeData gps_time;
|
|
GPSTimeGet(&gps_time);
|
|
uint32_t frsky_time = 0;
|
|
|
|
if (arg == 0) {
|
|
// encode date
|
|
frsky_time = 0x000000ff;
|
|
frsky_time |= gps_time.Day << 8;
|
|
frsky_time |= gps_time.Month << 16;
|
|
frsky_time |= (gps_time.Year % 100) << 24;
|
|
} else {
|
|
frsky_time = 0;
|
|
frsky_time |= gps_time.Second << 8;
|
|
frsky_time |= gps_time.Minute << 16;
|
|
frsky_time |= gps_time.Hour << 24;
|
|
}
|
|
*value = frsky_time;
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encodes ARM status and flight mode number as RPM value
|
|
* Since there is no RPM information in any UAVO available,
|
|
* we will intentionaly misuse this item to encode another useful information.
|
|
* It will encode flight status as three-digit number as follow:
|
|
* most left digit encodes arm status (1=armed, 0=disarmed)
|
|
* two most right digits encodes flight mode number (see FlightStatus UAVO FlightMode enum)
|
|
* To work this propperly on Taranis, you have to set Blades to "1" in telemetry setting
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_rpm(__attribute__((unused)) struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (FlightStatusHandle() == NULL) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
FlightStatusData flight_status;
|
|
FlightStatusGet(&flight_status);
|
|
|
|
*value = (flight_status.Armed == FLIGHTSTATUS_ARMED_ARMED) ? 200 : 100;
|
|
*value += flight_status.FlightMode;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Encode true airspeed(TAS)
|
|
* @param[out] value encoded value
|
|
* @param[in] test_presence_only true when function should only test for availability of this value
|
|
* @param[in] arg argument specified in frsky_value_items[]
|
|
* @returns true when value succesfully encoded or presence test passed
|
|
*/
|
|
bool frsky_encode_airspeed(__attribute__((unused)) struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, __attribute__((unused)) uint32_t arg)
|
|
{
|
|
if (AirspeedStateHandle() == NULL) {
|
|
return false;
|
|
}
|
|
if (test_presence_only) {
|
|
return true;
|
|
}
|
|
|
|
AirspeedStateData airspeed;
|
|
AirspeedStateGet(&airspeed);
|
|
int32_t frsky_speed = (int32_t)((airspeed.TrueAirspeed / KNOTS2M_PER_SECOND) * 10);
|
|
*value = (uint32_t)frsky_speed;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Performs byte stuffing and checksum calculation
|
|
* @param[out] obuff buffer where byte stuffed data will came in
|
|
* @param[in,out] chk checksum byte to update
|
|
* @param[in] byte
|
|
* @returns count of bytes inserted to obuff (1 or 2)
|
|
*/
|
|
uint8_t frsky_insert_byte(uint8_t *obuff, uint16_t *chk, uint8_t byte)
|
|
{
|
|
/* checksum calculation is based on data before byte-stuffing */
|
|
*chk += byte;
|
|
*chk += (*chk) >> 8;
|
|
*chk &= 0x00ff;
|
|
*chk += (*chk) >> 8;
|
|
*chk &= 0x00ff;
|
|
|
|
if (byte == 0x7e || byte == 0x7d) {
|
|
obuff[0] = 0x7d;
|
|
obuff[1] = byte &= ~0x20;
|
|
return 2;
|
|
}
|
|
|
|
obuff[0] = byte;
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Send u32 value dataframe to FrSky SmartPort bus
|
|
* @param[in] id FrSky value ID
|
|
* @param[in] value value
|
|
*/
|
|
int32_t frsky_send_frame(uintptr_t com, enum frsky_value_id id, uint32_t value,
|
|
bool send_prelude)
|
|
{
|
|
/* each call of frsky_insert_byte can add 2 bytes to the buffer at maximum
|
|
* and therefore the worst-case is 17 bytes total (the first byte 0x10 won't be
|
|
* escaped) */
|
|
uint8_t tx_data[17];
|
|
uint16_t chk = 0;
|
|
uint8_t cnt = 0;
|
|
|
|
if (send_prelude) {
|
|
tx_data[0] = 0x7e;
|
|
tx_data[1] = 0x98;
|
|
cnt = 2;
|
|
}
|
|
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, 0x10);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, (uint16_t)id & 0xff);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, ((uint16_t)id >> 8) & 0xff);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, value & 0xff);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, (value >> 8) & 0xff);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, (value >> 16) & 0xff);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, (value >> 24) & 0xff);
|
|
cnt += frsky_insert_byte(&tx_data[cnt], &chk, 0xff - chk);
|
|
|
|
PIOS_COM_SendBuffer(com, tx_data, cnt);
|
|
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
* @}
|
|
*/
|