diff --git a/flight/modules/UAVOHottBridge/inc/uavohottbridge.h b/flight/modules/UAVOHottBridge/inc/uavohottbridge.h
new file mode 100644
index 000000000..470ab6304
--- /dev/null
+++ b/flight/modules/UAVOHottBridge/inc/uavohottbridge.h
@@ -0,0 +1,379 @@
+/**
+ ******************************************************************************
+ * @addtogroup Modules
+ * @{
+ * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Telemetry Module
+ * @{
+ *
+ * @file uavohottbridge.h
+ * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
+ * Tau Labs, http://taulabs.org, Copyright (C) 2013
+ * @brief sends telemery data on HoTT request
+ *
+ * @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
+ */
+
+// timing variables
+#define IDLE_TIME 10 // idle line delay to prevent data crashes on telemetry line.
+#define DATA_TIME 3 // time between 2 transmitted bytes
+
+// sizes and lengths
+#define climbratesize 50 // defines size of ring buffer for climbrate calculation
+#define statussize 21 // number of characters in status line
+#define HOTT_MAX_MESSAGE_LENGTH 200
+
+// scale factors
+#define M_TO_CM 100 // scale m to cm or m/s to cm/s
+#define MS_TO_KMH 3.6f // scale m/s to km/h
+#define DEG_TO_UINT 0.5f // devide degrees by 2. then the value fits into a byte.
+
+// offsets. used to make transmitted values unsigned.
+#define OFFSET_ALTITUDE 500 // 500m
+#define OFFSET_CLIMBRATE 30000 // 30000cm/s or 300m/s
+#define OFFSET_CLIMBRATE3S 120 // 120m/s
+#define OFFSET_TEMPERATURE 20 // 20 degrees
+
+// Bits to invert display areas or values
+#define VARIO_INVERT_ALT (1 << 0) // altitude
+#define VARIO_INVERT_MAX (1 << 1) // max altitude
+#define VARIO_INVERT_MIN (1 << 2) // min altitude
+#define VARIO_INVERT_CR1S (1 << 3) // climbrate 1s
+#define VARIO_INVERT_CR3S (1 << 4) // climbrate 3s
+#define VARIO_INVERT_CR10S (1 << 5) // climbrate 10s
+
+#define GPS_INVERT_HDIST (1 << 0) // home distance
+#define GPS_INVERT_SPEED (1 << 1) // speed (kmh)
+#define GPS_INVERT_ALT (1 << 2) // altitude
+#define GPS_INVERT_CR1S (1 << 3) // climbrate 1s
+#define GPS_INVERT_CR3S (1 << 4) // climbrate 3s
+#define GPS_INVERT2_POS (1 << 0) // GPS postion values
+
+#define GAM_INVERT_CELL (1 << 0) // cell voltage
+#define GAM_INVERT_BATT1 (1 << 1) // battery 1 voltage
+#define GAM_INVERT_BATT2 (1 << 2) // battery 1 voltage
+#define GAM_INVERT_TEMP1 (1 << 3) // temperature 1
+#define GAM_INVERT_TEMP2 (1 << 4) // temperature 2
+#define GAM_INVERT_FUEL (1 << 5) // fuel
+#define GAM_INVERT2_CURRENT (1 << 0) // current
+#define GAM_INVERT2_VOLTAGE (1 << 1) // voltage
+#define GAM_INVERT2_ALT (1 << 2) // altitude
+#define GAM_INVERT2_CR1S (1 << 3) // climbrate 1s
+#define GAM_INVERT2_CR3S (1 << 4) // climbrate 3s
+
+#define EAM_INVERT_CAPACITY (1 << 0) // capacity
+#define EAM_INVERT_BATT1 (1 << 1) // battery 1 voltage
+#define EAM_INVERT_BATT2 (1 << 2) // battery 1 voltage
+#define EAM_INVERT_TEMP1 (1 << 3) // temperature 1
+#define EAM_INVERT_TEMP2 (1 << 4) // temperature 2
+#define EAM_INVERT_ALT (1 << 5) // altitude
+#define EAM_INVERT_CURRENT (1 << 6) // current
+#define EAM_INVERT_VOLTAGE (1 << 7) // voltage
+#define EAM_INVERT2_ALT (1 << 2) // altitude
+#define EAM_INVERT2_CR1S (1 << 3) // climbrate 1s
+#define EAM_INVERT2_CR3S (1 << 4) // climbrate 3s
+
+#define ESC_INVERT_VOLTAGE (1 << 0) // voltage
+#define ESC_INVERT_TEMP1 (1 << 1) // temperature 1
+#define ESC_INVERT_TEMP2 (1 << 2) // temperature 2
+#define ESC_INVERT_CURRENT (1 << 3) // current
+#define ESC_INVERT_RPM (1 << 4) // rpm
+#define ESC_INVERT_CAPACITY (1 << 5) // capacity
+#define ESC_INVERT_MAXCURRENT (1 << 6) // maximum current
+
+// message codes
+#define HOTT_TEXT_ID 0x7f // Text request
+#define HOTT_BINARY_ID 0x80 // Binary request
+#define HOTT_VARIO_ID 0x89 // Vario Module ID
+#define HOTT_VARIO_TEXT_ID 0x90 // Vario Module TEXT ID
+#define HOTT_GPS_ID 0x8a // GPS Module ID
+#define HOTT_GPS_TEXT_ID 0xa0 // GPS Module TEXT ID
+#define HOTT_ESC_ID 0x8c // ESC Module ID
+#define HOTT_ESC_TEXT_ID 0xc0 // ESC Module TEXT ID
+#define HOTT_GAM_ID 0x8d // General Air Module ID
+#define HOTT_GAM_TEXT_ID 0xd0 // General Air Module TEXT ID
+#define HOTT_EAM_ID 0x8e // Electric Air Module ID
+#define HOTT_EAM_TEXT_ID 0xe0 // Electric Air Module TEXT ID
+#define HOTT_TEXT_START 0x7b // Start byte Text mode
+#define HOTT_START 0x7c // Start byte Binary mode
+#define HOTT_STOP 0x7d // End byte
+#define HOTT_BUTTON_DEC 0xEB // minus button
+#define HOTT_BUTTON_INC 0xED // plus button
+#define HOTT_BUTTON_SET 0xE9 // set button
+#define HOTT_BUTTON_NIL 0x0F // esc button
+#define HOTT_BUTTON_NEXT 0xEE // next button
+#define HOTT_BUTTON_PREV 0xE7 // previous button
+
+// prefined signal tones or spoken announcments
+#define HOTT_TONE_A 1 // minimum speed
+#define HOTT_TONE_B 2 // sink rate 3 seconds
+#define HOTT_TONE_C 3 // sink rate 1 second
+#define HOTT_TONE_D 4 // maximum distance
+#define HOTT_TONE_E 5 // -
+#define HOTT_TONE_F 6 // minimum temperature sensor 1
+#define HOTT_TONE_G 7 // minimum temperature sensor 2
+#define HOTT_TONE_H 8 // maximum temperature sensor 1
+#define HOTT_TONE_I 9 // maximum temperature sensor 2
+#define HOTT_TONE_J 10 // overvoltage sensor 1
+#define HOTT_TONE_K 11 // overvoltage sensor 2
+#define HOTT_TONE_L 12 // maximum speed
+#define HOTT_TONE_M 13 // climb rate 3 seconds
+#define HOTT_TONE_N 14 // climb rate 1 second
+#define HOTT_TONE_O 15 // minimum height
+#define HOTT_TONE_P 16 // minimum input voltage
+#define HOTT_TONE_Q 17 // minimum cell voltage
+#define HOTT_TONE_R 18 // undervoltage sensor 1
+#define HOTT_TONE_S 19 // undervoltage sensor 2
+#define HOTT_TONE_T 20 // minimum rpm
+#define HOTT_TONE_U 21 // fuel reserve
+#define HOTT_TONE_V 22 // capacity
+#define HOTT_TONE_W 23 // maximum current
+#define HOTT_TONE_X 24 // maximum input voltage
+#define HOTT_TONE_Y 25 // maximum rpm
+#define HOTT_TONE_Z 26 // maximum height
+#define HOTT_TONE_20M 37 // 20 meters
+#define HOTT_TONE_40M 38 // 40 meters
+#define HOTT_TONE_60M 39 // 60 meters
+#define HOTT_TONE_80M 40 // 80 meters
+#define HOTT_TONE_100M 41 // 100 meters
+#define HOTT_TONE_42 42 // receiver voltage
+#define HOTT_TONE_43 43 // receiver temperature
+#define HOTT_TONE_200M 46 // 200 meters
+#define HOTT_TONE_400M 47 // 400 meters
+#define HOTT_TONE_600M 48 // 600 meters
+#define HOTT_TONE_800M 49 // 800 meters
+#define HOTT_TONE_1000M 50 // 10000 meters
+#define HOTT_TONE_51 51 // maximum servo temperature
+#define HOTT_TONE_52 52 // maximum servo position difference
+
+
+// Private types
+typedef struct {
+ uint8_t l;
+ uint8_t h;
+} uword_t;
+
+// Private structures
+struct telemetrydata {
+ HoTTBridgeSettingsData Settings;
+ AttitudeStateData Attitude;
+ BaroSensorData Baro;
+ FlightBatteryStateData Battery;
+ FlightStatusData FlightStatus;
+ GPSPositionSensorData GPS;
+ GPSTimeData GPStime;
+ GyroSensorData Gyro;
+ HomeLocationData Home;
+ PositionStateData Position;
+ SystemAlarmsData SysAlarms;
+ VelocityStateData Velocity;
+ int16_t climbratebuffer[climbratesize];
+ uint8_t climbrate_pointer;
+ float altitude;
+ float min_altitude;
+ float max_altitude;
+ float altitude_last;
+ float climbrate1s;
+ float climbrate3s;
+ float climbrate10s;
+ float homedistance;
+ float homecourse;
+ uint8_t last_armed;
+ char statusline[statussize];
+};
+
+// VARIO Module message structure
+struct hott_vario_message {
+ uint8_t start; // start byte
+ uint8_t sensor_id; // VARIO sensor ID
+ uint8_t warning; // 0…= warning beeps
+ uint8_t sensor_text_id; // VARIO sensor text ID
+ uint8_t alarm_inverse; // this inverts specific parts of display
+ uword_t altitude; // altitude (meters), offset 500, 500 == 0m
+ uword_t max_altitude; // max. altitude (meters)
+ uword_t min_altitude; // min. altitude (meters)
+ uword_t climbrate; // climb rate (0.01m/s), offset 30000, 30000 == 0.00m/s
+ uword_t climbrate3s; // climb rate (0.01m/3s)
+ uword_t climbrate10s; // climb rate (0.01m/10s)
+ uint8_t ascii[21]; // 21 chars of text
+ uint8_t ascii1; // ASCII Free character [1] (next to Alt)
+ uint8_t ascii2; // ASCII Free character [2] (next to Dir)
+ uint8_t ascii3; // ASCII Free character [3] (next to I)
+ int8_t compass; // 1=2°, -1=-2°
+ uint8_t version; // version number
+ uint8_t stop; // stop byte
+ uint8_t checksum; // Lower 8-bits of all bytes summed
+};
+
+// GPS Module message structure
+struct hott_gps_message {
+ uint8_t start; // start byte
+ uint8_t sensor_id; // GPS sensor ID
+ uint8_t warning; // 0…= warning beeps
+ uint8_t sensor_text_id; // GPS Sensor text mode ID
+ uint8_t alarm_inverse1; // this inverts specific parts of display
+ uint8_t alarm_inverse2;
+ uint8_t flight_direction; // flight direction (1 = 2°; 0° = north, 90° = east , 180° = south , 270° west)
+ uword_t gps_speed; // GPS speed (km/h)
+ uint8_t latitude_ns; // GPS latitude north/south (0 = N)
+ uword_t latitude_min; // GPS latitude (min)
+ uword_t latitude_sec; // GPS latitude (sec)
+ uint8_t longitude_ew; // GPS longitude east/west (0 = E)
+ uword_t longitude_min; // GPS longitude (min)
+ uword_t longitude_sec; // GPS longitude (sec)
+ uword_t distance; // distance from home location (meters)
+ uword_t altitude; // altitude (meters), offset 500, 500 == 0m
+ uword_t climbrate; // climb rate (0.01m/s), offset of 30000, 30000 = 0.00 m/s
+ uint8_t climbrate3s; // climb rate in (m/3s). offset of 120, 120 == 0m/3sec
+ uint8_t gps_num_sat; // GPS number of satelites
+ uint8_t gps_fix_char; // GPS FixChar ('D'=DGPS, '2'=2D, '3'=3D)
+ uint8_t home_direction; // home direction (1=2°, direction from starting point to model position)
+ int8_t angle_roll; // angle x-direction (roll 1=2°, 255=-2°)
+ int8_t angle_nick; // angle y-direction (nick)
+ int8_t angle_compass; // angle z-direction (yaw)
+ uint8_t gps_hour; // GPS time hours
+ uint8_t gps_min; // GPS time minutes
+ uint8_t gps_sec; // GPS time seconds
+ uint8_t gps_msec; // GPS time .sss
+ uword_t msl; // MSL or NN altitude
+ uint8_t vibration; // vibration
+ uint8_t ascii4; // ASCII Free Character [4] (next to home distance)
+ uint8_t ascii5; // ASCII Free Character [5] (next to home direction)
+ uint8_t ascii6; // ASCII Free Character [6] (next to number of sats)
+ uint8_t version; // version number (0=gps, 1=gyro, 255=multicopter)
+ uint8_t stop; // stop byte
+ uint8_t checksum; // Lower 8-bits of all bytes summed
+};
+
+// General Air Module message structure
+struct hott_gam_message {
+ uint8_t start; // start byte
+ uint8_t sensor_id; // GAM sensor ID
+ uint8_t warning; // 0…= warning beeps
+ uint8_t sensor_text_id; // EAM Sensor text mode ID
+ uint8_t alarm_inverse1; // this inverts specific parts of display
+ uint8_t alarm_inverse2;
+ uint8_t cell1; // cell voltages in 0.02V steps, 210 == 4.2V
+ uint8_t cell2;
+ uint8_t cell3;
+ uint8_t cell4;
+ uint8_t cell5;
+ uint8_t cell6;
+ uword_t batt1_voltage; // battery sensor 1 in 0.1V steps, 50 == 5.5V
+ uword_t batt2_voltage; // battery sensor 2 voltage
+ uint8_t temperature1; // temperature 1 in °C, offset of 20, 20 == 0°C
+ uint8_t temperature2; // temperature 2
+ uint8_t fuel_procent; // fuel capacity in %, values from 0..100
+ uword_t fuel_ml; // fuel capacity in ml, values from 0..65535
+ uword_t rpm; // rpm, scale factor 10, 300 == 3000rpm
+ uword_t altitude; // altitude in meters, offset of 500, 500 == 0m
+ uword_t climbrate; // climb rate (0.01m/s), offset of 30000, 30000 = 0.00 m/s
+ uint8_t climbrate3s; // climb rate (m/3sec). offset of 120, 120 == 0m/3sec
+ uword_t current; // current in 0.1A steps
+ uword_t voltage; // main power voltage in 0.1V steps
+ uword_t capacity; // used battery capacity in 10mAh steps
+ uword_t speed; // speed in km/h
+ uint8_t min_cell_volt; // lowest cell voltage in 20mV steps. 124 == 2.48V
+ uint8_t min_cell_volt_num; // number of the cell with the lowest voltage
+ uword_t rpm2; // rpm2 in 10 rpm steps, 300 == 3000rpm
+ uint8_t g_error_number; // general error number (Voice error == 12)
+ uint8_t pressure; // pressure up to 15bar, 0.1bar steps
+ uint8_t version; // version number
+ uint8_t stop; // stop byte
+ uint8_t checksum; // Lower 8-bits of all bytes summed
+};
+
+// Electric Air Module message structure
+struct hott_eam_message {
+ uint8_t start; // Start byte
+ uint8_t sensor_id; // EAM sensor id
+ uint8_t warning;
+ uint8_t sensor_text_id; // EAM Sensor text mode ID
+ uint8_t alarm_inverse1; // this inverts specific parts of display
+ uint8_t alarm_inverse2;
+ uint8_t cell1_L; // cell voltages of the lower battery
+ uint8_t cell2_L;
+ uint8_t cell3_L;
+ uint8_t cell4_L;
+ uint8_t cell5_L;
+ uint8_t cell6_L;
+ uint8_t cell7_L;
+ uint8_t cell1_H; // cell voltages of higher battery
+ uint8_t cell2_H;
+ uint8_t cell3_H;
+ uint8_t cell4_H;
+ uint8_t cell5_H;
+ uint8_t cell6_H;
+ uint8_t cell7_H;
+ uword_t batt1_voltage; // battery sensor 1 voltage, in steps of 0.02V
+ uword_t batt2_voltage; // battery sensor 2 voltage, in steps of 0.02V
+ uint8_t temperature1; // temperature sensor 1. 20 = 0 degrees
+ uint8_t temperature2; // temperature sensor 2. 20 = 0 degrees
+ uword_t altitude; // altitude (meters). 500 = 0 meters
+ uword_t current; // current (A) in steps of 0.1A
+ uword_t voltage; // main power voltage in steps of 0.1V
+ uword_t capacity; // used battery capacity in steps of 10mAh
+ uword_t climbrate; // climb rate in 0.01m/s. 0m/s = 30000
+ uint8_t climbrate3s; // climb rate in m/3sec. 0m/3sec = 120
+ uword_t rpm; // rpm in steps of 10 rpm
+ uint8_t electric_min; // estaminated flight time in minutes.
+ uint8_t electric_sec; // estaminated flight time in seconds.
+ uword_t speed; // speed in km/h in steps of 1 km/h
+ uint8_t stop; // Stop byte
+ uint8_t checksum; // Lower 8-bits of all bytes summed.
+};
+
+// ESC Module message structure
+struct hott_esc_message {
+ uint8_t start; // Start byte
+ uint8_t sensor_id; // EAM sensor id
+ uint8_t warning;
+ uint8_t sensor_text_id; // ESC Sensor text mode ID
+ uint8_t alarm_inverse1;
+ uint8_t alarm_inverse2;
+ uword_t batt_voltage; // battery voltage in steps of 0.1V
+ uword_t min_batt_voltage; // min battery voltage
+ uword_t batt_capacity; // used battery capacity in steps of 10mAh
+ uint8_t temperatureESC; // temperature of ESC . 20 = 0 degrees
+ uint8_t max_temperatureESC; // max temperature of ESC
+ uword_t current; // Current in steps of 0.1A
+ uword_t max_current; // maximal current
+ uword_t rpm; // rpm in steps of 10 rpm
+ uword_t max_rpm; // max rpm
+ uint8_t temperatureMOT; // motor temperature
+ uint8_t max_temperatureMOT; // maximal motor temperature
+ uint8_t dummy[19]; // 19 dummy bytes
+ uint8_t stop; // Stop byte
+ uint8_t checksum; // Lower 8-bits of all bytes summed.
+};
+
+// TEXT message structure
+struct hott_text_message {
+ uint8_t start; // Start byte
+ uint8_t sensor_id; // TEXT id
+ uint8_t warning;
+ uint8_t text[21][8]; // text field 21 columns and 8 rows (bit 7=1 for inverse display)
+ uint8_t stop; // Stop byte
+ uint8_t checksum; // Lower 8-bits of all bytes summed.
+};
+
+
+/**
+ * @}
+ * @}
+ */
diff --git a/flight/modules/UAVOHottBridge/uavohottbridge.c b/flight/modules/UAVOHottBridge/uavohottbridge.c
new file mode 100644
index 000000000..9342e0eab
--- /dev/null
+++ b/flight/modules/UAVOHottBridge/uavohottbridge.c
@@ -0,0 +1,962 @@
+/**
+ ******************************************************************************
+ * @addtogroup OpenPilotModules OpenPilot Modules
+ * @{
+ * @addtogroup UAVOHoTTBridge UAVO to HoTT Bridge Telemetry Module
+ * @{
+ *
+ * @file uavohottbridge.c
+ * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
+ * Tau Labs, http://taulabs.org, Copyright (C) 2013-2014
+ * @brief sends telemery data on HoTT request
+ *
+ * @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
+ *
+ * Additional note on redistribution: The copyright and license notices above
+ * must be maintained in each individual source file that is a derivative work
+ * of this source file; otherwise redistribution is prohibited.
+ */
+
+#include "openpilot.h"
+#include "hwsettings.h"
+#include "taskinfo.h"
+#include "callbackinfo.h"
+#include "hottbridgesettings.h"
+#include "attitudestate.h"
+#include "barosensor.h"
+#include "flightbatterystate.h"
+#include "flightstatus.h"
+#include "gyrosensor.h"
+#include "gpspositionsensor.h"
+#include "gpstime.h"
+#include "homelocation.h"
+#include "positionstate.h"
+#include "systemalarms.h"
+#include "velocitystate.h"
+#include "hottbridgestatus.h"
+#include "hottbridgesettings.h"
+#include "objectpersistence.h"
+#include "pios_sensors.h"
+#include "uavohottbridge.h"
+
+#if defined(PIOS_INCLUDE_HOTT_BRIDGE)
+
+#if defined(PIOS_HoTT_STACK_SIZE)
+#define STACK_SIZE_BYTES PIOS_HoTT_STACK_SIZE
+#else
+#define STACK_SIZE_BYTES 2048
+#endif
+#define TASK_PRIORITY CALLBACK_TASK_AUXILIARY
+
+static bool module_enabled = false;
+
+// Private variables
+static bool module_enabled;
+static struct telemetrydata *telestate;
+static HoTTBridgeStatusData status;
+
+// Private functions
+static void uavoHoTTBridgeTask(void *parameters);
+static uint16_t build_VARIO_message(struct hott_vario_message *msg);
+static uint16_t build_GPS_message(struct hott_gps_message *msg);
+static uint16_t build_GAM_message(struct hott_gam_message *msg);
+static uint16_t build_EAM_message(struct hott_eam_message *msg);
+static uint16_t build_ESC_message(struct hott_esc_message *msg);
+static uint16_t build_TEXT_message(struct hott_text_message *msg);
+static uint8_t calc_checksum(uint8_t *data, uint16_t size);
+static uint8_t generate_warning();
+static void update_telemetrydata();
+static void convert_long2gps(int32_t value, uint8_t *dir, uword_t *min, uword_t *sec);
+static uint8_t scale_float2uint8(float value, float scale, float offset);
+static int8_t scale_float2int8(float value, float scale, float offset);
+static uword_t scale_float2uword(float value, float scale, float offset);
+
+/**
+ * Module start routine automatically called after initialization routine
+ * @return 0 when was successful
+ */
+static int32_t uavoHoTTBridgeStart(void)
+{
+ status.TxPackets = 0;
+ status.RxPackets = 0;
+ status.TxFail = 0;
+ status.RxFail = 0;
+
+
+ // Start task
+ if (module_enabled) {
+ xTaskHandle taskHandle;
+
+ xTaskCreate(uavoHoTTBridgeTask, "uavoHoTTBridge", STACK_SIZE_BYTES / 4, NULL, TASK_PRIORITY, &taskHandle);
+ PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_UAVOHOTTBRIDGE, taskHandle);
+ }
+
+ return 0;
+}
+
+/**
+ * Module initialization routine
+ * @return 0 when initialization was successful
+ */
+static int32_t uavoHoTTBridgeInitialize(void)
+{
+ if (PIOS_COM_HOTT) {
+ module_enabled = true;
+ // HoTT telemetry baudrate is fixed to 19200
+
+ PIOS_COM_ChangeBaud(PIOS_COM_HOTT, 19200);
+ PIOS_COM_SetHalfDuplex(PIOS_COM_HOTT, true);
+ HoTTBridgeSettingsInitialize();
+ HoTTBridgeStatusInitialize();
+
+ // allocate memory for telemetry data
+ telestate = (struct telemetrydata *)pios_malloc(sizeof(*telestate));
+
+ if (telestate == NULL) {
+ // there is not enough free memory. the module could not run.
+ module_enabled = false;
+ return -1;
+ }
+ } else {
+ module_enabled = false;
+ }
+ return 0;
+}
+MODULE_INITCALL(uavoHoTTBridgeInitialize, uavoHoTTBridgeStart);
+
+/**
+ * Main task. It does not return.
+ */
+static void uavoHoTTBridgeTask(__attribute__((unused)) void *parameters)
+{
+ uint8_t rx_buffer[2];
+ uint8_t tx_buffer[HOTT_MAX_MESSAGE_LENGTH];
+ uint16_t message_size;
+
+ // clear all state values
+ memset(telestate, 0, sizeof(*telestate));
+
+ // initialize timer variables
+ portTickType lastSysTime = xTaskGetTickCount();
+ // idle delay between telemetry request and answer
+ uint32_t idledelay = IDLE_TIME;
+ // data delay between transmitted bytes
+ uint32_t datadelay = DATA_TIME;
+
+ // work on hott telemetry. endless loop.
+ while (1) {
+ // clear message size on every loop before processing
+ message_size = 0;
+
+ // shift receiver buffer. make room for one byte.
+ rx_buffer[1] = rx_buffer[0];
+
+ // wait for a byte of telemetry request in data delay interval
+ while (PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, rx_buffer, 1, 0) == 0) {
+ vTaskDelayUntil(&lastSysTime, datadelay / portTICK_RATE_MS);
+ }
+ // set start trigger point
+ lastSysTime = xTaskGetTickCount();
+
+ // examine received data stream
+ if (rx_buffer[1] == HOTT_BINARY_ID) {
+ // first received byte looks like a binary request. check second received byte for a sensor id.
+ switch (rx_buffer[0]) {
+ case HOTT_VARIO_ID:
+ message_size = build_VARIO_message((struct hott_vario_message *)tx_buffer);
+ break;
+ case HOTT_GPS_ID:
+ message_size = build_GPS_message((struct hott_gps_message *)tx_buffer);
+ break;
+ case HOTT_GAM_ID:
+ message_size = build_GAM_message((struct hott_gam_message *)tx_buffer);
+ break;
+ case HOTT_EAM_ID:
+ message_size = build_EAM_message((struct hott_eam_message *)tx_buffer);
+ break;
+ case HOTT_ESC_ID:
+ message_size = build_ESC_message((struct hott_esc_message *)tx_buffer);
+ break;
+ default:
+ message_size = 0;
+ }
+ } else if (rx_buffer[1] == HOTT_TEXT_ID) {
+ // first received byte looks like a text request. check second received byte for a valid button.
+ switch (rx_buffer[0]) {
+ case HOTT_BUTTON_DEC:
+ case HOTT_BUTTON_INC:
+ case HOTT_BUTTON_SET:
+ case HOTT_BUTTON_NIL:
+ case HOTT_BUTTON_NEXT:
+ case HOTT_BUTTON_PREV:
+ message_size = build_TEXT_message((struct hott_text_message *)tx_buffer);
+ break;
+ default:
+ message_size = 0;
+ }
+ }
+
+ // check if a message is in the transmit buffer.
+ if (message_size > 0) {
+ status.RxPackets++;
+
+ // check idle line before transmit. pause, then check receiver buffer
+ vTaskDelayUntil(&lastSysTime, idledelay / portTICK_RATE_MS);
+
+ if (PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, rx_buffer, 1, 0) == 0) {
+ // nothing received means idle line. ready to transmit the requested message
+ for (int i = 0; i < message_size; i++) {
+ // send message content with pause between each byte
+ PIOS_COM_SendCharNonBlocking(PIOS_COM_HOTT, tx_buffer[i]);
+ // grab possible incoming loopback data and throw it away
+ PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, rx_buffer, sizeof(rx_buffer), 0);
+ vTaskDelayUntil(&lastSysTime, datadelay / portTICK_RATE_MS);
+ }
+ status.TxPackets++;
+
+
+ // after transmitting the message, any loopback data needs to be cleaned up.
+ vTaskDelayUntil(&lastSysTime, idledelay / portTICK_RATE_MS);
+ PIOS_COM_ReceiveBuffer(PIOS_COM_HOTT, tx_buffer, message_size, 0);
+ } else {
+ status.RxFail++;
+ }
+ HoTTBridgeStatusSet(&status);
+ }
+ }
+}
+
+/**
+ * Build requested answer messages.
+ * \return value sets message size
+ */
+uint16_t build_VARIO_message(struct hott_vario_message *msg)
+{
+ update_telemetrydata();
+
+ if (telestate->Settings.Sensor.VARIO == HOTTBRIDGESETTINGS_SENSOR_DISABLED) {
+ return 0;
+ }
+
+ // clear message buffer
+ memset(msg, 0, sizeof(*msg));
+
+ // message header
+ msg->start = HOTT_START;
+ msg->stop = HOTT_STOP;
+ msg->sensor_id = HOTT_VARIO_ID;
+ msg->warning = generate_warning();
+ msg->sensor_text_id = HOTT_VARIO_TEXT_ID;
+
+ // alarm inverse bits. invert display areas on limits
+ msg->alarm_inverse |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? VARIO_INVERT_ALT : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? VARIO_INVERT_ALT : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? VARIO_INVERT_MAX : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? VARIO_INVERT_MIN : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? VARIO_INVERT_CR1S : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? VARIO_INVERT_CR1S : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? VARIO_INVERT_CR3S : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? VARIO_INVERT_CR3S : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate10s) ? VARIO_INVERT_CR10S : 0;
+ msg->alarm_inverse |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate10s) ? VARIO_INVERT_CR10S : 0;
+
+ // altitude relative to ground
+ msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE);
+ msg->min_altitude = scale_float2uword(telestate->min_altitude, 1, OFFSET_ALTITUDE);
+ msg->max_altitude = scale_float2uword(telestate->max_altitude, 1, OFFSET_ALTITUDE);
+
+ // climbrate
+ msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE);
+ msg->climbrate3s = scale_float2uword(telestate->climbrate3s, M_TO_CM, OFFSET_CLIMBRATE);
+ msg->climbrate10s = scale_float2uword(telestate->climbrate10s, M_TO_CM, OFFSET_CLIMBRATE);
+
+ // compass
+ msg->compass = scale_float2int8(telestate->Attitude.Yaw, DEG_TO_UINT, 0);
+
+ // statusline
+ memcpy(msg->ascii, telestate->statusline, sizeof(msg->ascii));
+
+ // free display characters
+ msg->ascii1 = 0;
+ msg->ascii2 = 0;
+ msg->ascii3 = 0;
+
+ msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg));
+ return sizeof(*msg);
+}
+
+uint16_t build_GPS_message(struct hott_gps_message *msg)
+{
+ update_telemetrydata();
+
+ if (telestate->Settings.Sensor.GPS == HOTTBRIDGESETTINGS_SENSOR_DISABLED) {
+ return 0;
+ }
+
+ // clear message buffer
+ memset(msg, 0, sizeof(*msg));
+
+ // message header
+ msg->start = HOTT_START;
+ msg->stop = HOTT_STOP;
+ msg->sensor_id = HOTT_GPS_ID;
+ msg->warning = generate_warning();
+ msg->sensor_text_id = HOTT_GPS_TEXT_ID;
+
+ // alarm inverse bits. invert display areas on limits
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxDistance < telestate->homedistance) ? GPS_INVERT_HDIST : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MinSpeed > telestate->GPS.Groundspeed) ? GPS_INVERT_SPEED : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxSpeed < telestate->GPS.Groundspeed) ? GPS_INVERT_SPEED : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? GPS_INVERT_ALT : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? GPS_INVERT_ALT : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? GPS_INVERT_CR1S : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? GPS_INVERT_CR1S : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? GPS_INVERT_CR3S : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? GPS_INVERT_CR3S : 0;
+ msg->alarm_inverse2 |= (telestate->SysAlarms.Alarm.GPS != SYSTEMALARMS_ALARM_OK) ? GPS_INVERT2_POS : 0;
+
+ // gps direction, groundspeed and postition
+ msg->flight_direction = scale_float2uint8(telestate->GPS.Heading, DEG_TO_UINT, 0);
+ msg->gps_speed = scale_float2uword(telestate->GPS.Groundspeed, MS_TO_KMH, 0);
+ convert_long2gps(telestate->GPS.Latitude, &msg->latitude_ns, &msg->latitude_min, &msg->latitude_sec);
+ convert_long2gps(telestate->GPS.Longitude, &msg->longitude_ew, &msg->longitude_min, &msg->longitude_sec);
+
+ // homelocation distance, course and state
+ msg->distance = scale_float2uword(telestate->homedistance, 1, 0);
+ msg->home_direction = scale_float2uint8(telestate->homecourse, DEG_TO_UINT, 0);
+ msg->ascii5 = (telestate->Home.Set ? 'H' : '-');
+
+ // altitude relative to ground and climb rate
+ msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE);
+ msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE);
+ msg->climbrate3s = scale_float2uint8(telestate->climbrate3s, 1, OFFSET_CLIMBRATE3S);
+
+ // number of satellites,gps fix and state
+ msg->gps_num_sat = telestate->GPS.Satellites;
+ switch (telestate->GPS.Status) {
+ case GPSPOSITIONSENSOR_STATUS_FIX2D:
+ msg->gps_fix_char = '2';
+ break;
+ case GPSPOSITIONSENSOR_STATUS_FIX3D:
+ msg->gps_fix_char = '3';
+ break;
+ default:
+ msg->gps_fix_char = 0;
+ }
+ switch (telestate->SysAlarms.Alarm.GPS) {
+ case SYSTEMALARMS_ALARM_UNINITIALISED:
+ msg->ascii6 = 0;
+ // if there is no gps, show compass flight direction
+ msg->flight_direction = scale_float2int8((telestate->Attitude.Yaw > 0) ? telestate->Attitude.Yaw : 360 + telestate->Attitude.Yaw, DEG_TO_UINT, 0);
+ break;
+ case SYSTEMALARMS_ALARM_OK:
+ msg->ascii6 = '.';
+ break;
+ case SYSTEMALARMS_ALARM_WARNING:
+ msg->ascii6 = '?';
+ break;
+ case SYSTEMALARMS_ALARM_ERROR:
+ case SYSTEMALARMS_ALARM_CRITICAL:
+ msg->ascii6 = '!';
+ break;
+ default:
+ msg->ascii6 = 0;
+ }
+
+ // model angles
+ msg->angle_roll = scale_float2int8(telestate->Attitude.Roll, DEG_TO_UINT, 0);
+ msg->angle_nick = scale_float2int8(telestate->Attitude.Pitch, DEG_TO_UINT, 0);
+ msg->angle_compass = scale_float2int8(telestate->Attitude.Yaw, DEG_TO_UINT, 0);
+
+ // gps time
+ msg->gps_hour = telestate->GPStime.Hour;
+ msg->gps_min = telestate->GPStime.Minute;
+ msg->gps_sec = telestate->GPStime.Second;
+ msg->gps_msec = 0;
+
+ // gps MSL (NN) altitude MSL
+ msg->msl = scale_float2uword(telestate->GPS.Altitude, 1, 0);
+
+ // free display chararacter
+ msg->ascii4 = 0;
+
+ msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg));
+ return sizeof(*msg);
+}
+
+uint16_t build_GAM_message(struct hott_gam_message *msg)
+{
+ update_telemetrydata();
+
+ if (telestate->Settings.Sensor.GAM == HOTTBRIDGESETTINGS_SENSOR_DISABLED) {
+ return 0;
+ }
+
+ // clear message buffer
+ memset(msg, 0, sizeof(*msg));
+
+ // message header
+ msg->start = HOTT_START;
+ msg->stop = HOTT_STOP;
+ msg->sensor_id = HOTT_GAM_ID;
+ msg->warning = generate_warning();
+ msg->sensor_text_id = HOTT_GAM_TEXT_ID;
+
+ // alarm inverse bits. invert display areas on limits
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxCurrent < telestate->Battery.Current) ? GAM_INVERT2_CURRENT : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MinPowerVoltage > telestate->Battery.Voltage) ? GAM_INVERT2_VOLTAGE : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxPowerVoltage < telestate->Battery.Voltage) ? GAM_INVERT2_VOLTAGE : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? GAM_INVERT2_ALT : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? GAM_INVERT2_ALT : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? GAM_INVERT2_CR1S : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? GAM_INVERT2_CR1S : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? GAM_INVERT2_CR3S : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? GAM_INVERT2_CR3S : 0;
+
+ // temperatures
+ msg->temperature1 = scale_float2uint8(telestate->Gyro.temperature, 1, OFFSET_TEMPERATURE);
+ msg->temperature2 = scale_float2uint8(telestate->Baro.Temperature, 1, OFFSET_TEMPERATURE);
+
+ // altitude
+ msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE);
+
+ // climbrate
+ msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE);
+ msg->climbrate3s = scale_float2uint8(telestate->climbrate3s, 1, OFFSET_CLIMBRATE3S);
+
+ // main battery
+ float voltage = (telestate->Battery.Voltage > 0) ? telestate->Battery.Voltage : 0;
+ float current = (telestate->Battery.Current > 0) ? telestate->Battery.Current : 0;
+ float energy = (telestate->Battery.ConsumedEnergy > 0) ? telestate->Battery.ConsumedEnergy : 0;
+ msg->voltage = scale_float2uword(voltage, 10, 0);
+ msg->current = scale_float2uword(current, 10, 0);
+ msg->capacity = scale_float2uword(energy, 0.1f, 0);
+
+ // pressure kPa to 0.1Bar
+ msg->pressure = scale_float2uint8(telestate->Baro.Pressure, 0.1f, 0);
+
+ msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg));
+ return sizeof(*msg);
+}
+
+uint16_t build_EAM_message(struct hott_eam_message *msg)
+{
+ update_telemetrydata();
+
+ if (telestate->Settings.Sensor.EAM == HOTTBRIDGESETTINGS_SENSOR_DISABLED) {
+ return 0;
+ }
+
+ // clear message buffer
+ memset(msg, 0, sizeof(*msg));
+
+ // message header
+ msg->start = HOTT_START;
+ msg->stop = HOTT_STOP;
+ msg->sensor_id = HOTT_EAM_ID;
+ msg->warning = generate_warning();
+ msg->sensor_text_id = HOTT_EAM_TEXT_ID;
+
+ // alarm inverse bits. invert display areas on limits
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxUsedCapacity < telestate->Battery.ConsumedEnergy) ? EAM_INVERT_CAPACITY : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxCurrent < telestate->Battery.Current) ? EAM_INVERT_CURRENT : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MinPowerVoltage > telestate->Battery.Voltage) ? EAM_INVERT_VOLTAGE : 0;
+ msg->alarm_inverse1 |= (telestate->Settings.Limit.MaxPowerVoltage < telestate->Battery.Voltage) ? EAM_INVERT_VOLTAGE : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MinHeight > telestate->altitude) ? EAM_INVERT2_ALT : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.MaxHeight < telestate->altitude) ? EAM_INVERT2_ALT : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s) ? EAM_INVERT2_CR1S : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference1 < telestate->climbrate1s) ? EAM_INVERT2_CR1S : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s) ? EAM_INVERT2_CR3S : 0;
+ msg->alarm_inverse2 |= (telestate->Settings.Limit.PosDifference2 < telestate->climbrate3s) ? EAM_INVERT2_CR3S : 0;
+
+ // main battery
+ float voltage = (telestate->Battery.Voltage > 0) ? telestate->Battery.Voltage : 0;
+ float current = (telestate->Battery.Current > 0) ? telestate->Battery.Current : 0;
+ float energy = (telestate->Battery.ConsumedEnergy > 0) ? telestate->Battery.ConsumedEnergy : 0;
+ msg->voltage = scale_float2uword(voltage, 10, 0);
+ msg->current = scale_float2uword(current, 10, 0);
+ msg->capacity = scale_float2uword(energy, 0.1f, 0);
+
+ // temperatures
+ msg->temperature1 = scale_float2uint8(telestate->Gyro.temperature, 1, OFFSET_TEMPERATURE);
+ msg->temperature2 = scale_float2uint8(telestate->Baro.Temperature, 1, OFFSET_TEMPERATURE);
+
+ // altitude
+ msg->altitude = scale_float2uword(telestate->altitude, 1, OFFSET_ALTITUDE);
+
+ // climbrate
+ msg->climbrate = scale_float2uword(telestate->climbrate1s, M_TO_CM, OFFSET_CLIMBRATE);
+ msg->climbrate3s = scale_float2uint8(telestate->climbrate3s, 1, OFFSET_CLIMBRATE3S);
+
+ // flight time
+ float flighttime = (telestate->Battery.EstimatedFlightTime <= 5999) ? telestate->Battery.EstimatedFlightTime : 5999;
+ msg->electric_min = flighttime / 60;
+ msg->electric_sec = flighttime - 60 * msg->electric_min;
+
+ msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg));
+ return sizeof(*msg);
+}
+
+uint16_t build_ESC_message(struct hott_esc_message *msg)
+{
+ update_telemetrydata();
+
+ if (telestate->Settings.Sensor.ESC == HOTTBRIDGESETTINGS_SENSOR_DISABLED) {
+ return 0;
+ }
+
+ // clear message buffer
+ memset(msg, 0, sizeof(*msg));
+
+ // message header
+ msg->start = HOTT_START;
+ msg->stop = HOTT_STOP;
+ msg->sensor_id = HOTT_ESC_ID;
+ msg->warning = 0;
+ msg->sensor_text_id = HOTT_ESC_TEXT_ID;
+
+ // main batterie
+ float voltage = (telestate->Battery.Voltage > 0) ? telestate->Battery.Voltage : 0;
+ float current = (telestate->Battery.Current > 0) ? telestate->Battery.Current : 0;
+ float max_current = (telestate->Battery.PeakCurrent > 0) ? telestate->Battery.PeakCurrent : 0;
+ float energy = (telestate->Battery.ConsumedEnergy > 0) ? telestate->Battery.ConsumedEnergy : 0;
+ msg->batt_voltage = scale_float2uword(voltage, 10, 0);
+ msg->current = scale_float2uword(current, 10, 0);
+ msg->max_current = scale_float2uword(max_current, 10, 0);
+ msg->batt_capacity = scale_float2uword(energy, 0.1f, 0);
+
+ // temperatures
+ msg->temperatureESC = scale_float2uint8(telestate->Gyro.temperature, 1, OFFSET_TEMPERATURE);
+ msg->max_temperatureESC = scale_float2uint8(0, 1, OFFSET_TEMPERATURE);
+ msg->temperatureMOT = scale_float2uint8(telestate->Baro.Temperature, 1, OFFSET_TEMPERATURE);
+ msg->max_temperatureMOT = scale_float2uint8(0, 1, OFFSET_TEMPERATURE);
+
+ msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg));
+ return sizeof(*msg);
+}
+
+uint16_t build_TEXT_message(struct hott_text_message *msg)
+{
+ update_telemetrydata();
+
+ // clear message buffer
+ memset(msg, 0, sizeof(*msg));
+
+ // message header
+ msg->start = HOTT_START;
+ msg->stop = HOTT_STOP;
+ msg->sensor_id = HOTT_TEXT_ID;
+
+ msg->checksum = calc_checksum((uint8_t *)msg, sizeof(*msg));
+ return sizeof(*msg);
+}
+
+/**
+ * update telemetry data
+ * this is called on every telemetry request
+ * calling interval is 200ms depending on TX
+ * 200ms telemetry request is used as time base for timed calculations (5Hz interval)
+ */
+void update_telemetrydata()
+{
+ // update all available data
+ if (HoTTBridgeSettingsHandle() != NULL) {
+ HoTTBridgeSettingsGet(&telestate->Settings);
+ }
+ if (AttitudeStateHandle() != NULL) {
+ AttitudeStateGet(&telestate->Attitude);
+ }
+ if (BaroSensorHandle() != NULL) {
+ BaroSensorGet(&telestate->Baro);
+ }
+ if (FlightBatteryStateHandle() != NULL) {
+ FlightBatteryStateGet(&telestate->Battery);
+ }
+ if (FlightStatusHandle() != NULL) {
+ FlightStatusGet(&telestate->FlightStatus);
+ }
+ if (GPSPositionSensorHandle() != NULL) {
+ GPSPositionSensorGet(&telestate->GPS);
+ }
+ if (GPSTimeHandle() != NULL) {
+ GPSTimeGet(&telestate->GPStime);
+ }
+ if (GyroSensorHandle() != NULL) {
+ GyroSensorGet(&telestate->Gyro);
+ }
+ if (HomeLocationHandle() != NULL) {
+ HomeLocationGet(&telestate->Home);
+ }
+ if (PositionStateHandle() != NULL) {
+ PositionStateGet(&telestate->Position);
+ }
+ if (SystemAlarmsHandle() != NULL) {
+ SystemAlarmsGet(&telestate->SysAlarms);
+ }
+ if (VelocityStateHandle() != NULL) {
+ VelocityStateGet(&telestate->Velocity);
+ }
+
+ // send actual climbrate value to ring buffer as mm per 0.2s values
+ uint8_t n = telestate->climbrate_pointer;
+ telestate->climbratebuffer[telestate->climbrate_pointer++] = -telestate->Velocity.Down * 200;
+ telestate->climbrate_pointer %= climbratesize;
+
+ // calculate avarage climbrates in meters per 1, 3 and 10 second(s) based on 200ms interval
+ telestate->climbrate1s = 0;
+ telestate->climbrate3s = 0;
+ telestate->climbrate10s = 0;
+ for (uint8_t i = 0; i < climbratesize; i++) {
+ telestate->climbrate1s += (i < 5) ? telestate->climbratebuffer[n] : 0;
+ telestate->climbrate3s += (i < 15) ? telestate->climbratebuffer[n] : 0;
+ telestate->climbrate10s += (i < 50) ? telestate->climbratebuffer[n] : 0;
+ n += climbratesize - 1;
+ n %= climbratesize;
+ }
+ telestate->climbrate1s = telestate->climbrate1s / 1000;
+ telestate->climbrate3s = telestate->climbrate3s / 1000;
+ telestate->climbrate10s = telestate->climbrate10s / 1000;
+
+ // set altitude offset and clear min/max values when arming
+ if ((telestate->FlightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING) || ((telestate->last_armed != FLIGHTSTATUS_ARMED_ARMED) && (telestate->FlightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED))) {
+ telestate->min_altitude = 0;
+ telestate->max_altitude = 0;
+ }
+ telestate->last_armed = telestate->FlightStatus.Armed;
+
+ // calculate altitude relative to start position
+ telestate->altitude = -telestate->Position.Down;
+
+ // check and set min/max values when armed.
+ if (telestate->FlightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED) {
+ if (telestate->min_altitude > telestate->altitude) {
+ telestate->min_altitude = telestate->altitude;
+ }
+ if (telestate->max_altitude < telestate->altitude) {
+ telestate->max_altitude = telestate->altitude;
+ }
+ }
+
+ // gps home position and course
+ telestate->homedistance = sqrtf(telestate->Position.North * telestate->Position.North + telestate->Position.East * telestate->Position.East);
+ telestate->homecourse = acosf(-telestate->Position.North / telestate->homedistance) / 3.14159265f * 180;
+ if (telestate->Position.East > 0) {
+ telestate->homecourse = 360 - telestate->homecourse;
+ }
+
+ // statusline
+ const char *txt_unknown = "unknown";
+ const char *txt_manual = "Manual";
+ const char *txt_stabilized1 = "Stabilized1";
+ const char *txt_stabilized2 = "Stabilized2";
+ const char *txt_stabilized3 = "Stabilized3";
+ const char *txt_stabilized4 = "Stabilized4";
+ const char *txt_stabilized5 = "Stabilized5";
+ const char *txt_stabilized6 = "Stabilized6";
+ const char *txt_positionhold = "PositionHold";
+ const char *txt_courselock = "CourseLock";
+ const char *txt_velocityroam = "VelocityRoam";
+ const char *txt_homeleash = "HomeLeash";
+ const char *txt_absoluteposition = "AbsolutePosition";
+ const char *txt_returntobase = "ReturnToBase";
+ const char *txt_land = "Land";
+ const char *txt_pathplanner = "PathPlanner";
+ const char *txt_poi = "PointOfInterest";
+ const char *txt_autocruise = "AutoCruise";
+ const char *txt_autotakeoff = "AutoTakeOff";
+ const char *txt_autotune = "Autotune";
+ const char *txt_disarmed = "Disarmed";
+ const char *txt_arming = "Arming";
+ const char *txt_armed = "Armed";
+
+ const char *txt_flightmode;
+ switch (telestate->FlightStatus.FlightMode) {
+ case FLIGHTSTATUS_FLIGHTMODE_MANUAL:
+ txt_flightmode = txt_manual;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_STABILIZED1:
+ txt_flightmode = txt_stabilized1;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_STABILIZED2:
+ txt_flightmode = txt_stabilized2;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_STABILIZED3:
+ txt_flightmode = txt_stabilized3;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_STABILIZED4:
+ txt_flightmode = txt_stabilized4;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_STABILIZED5:
+ txt_flightmode = txt_stabilized5;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_STABILIZED6:
+ txt_flightmode = txt_stabilized6;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD:
+ txt_flightmode = txt_positionhold;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_COURSELOCK:
+ txt_flightmode = txt_courselock;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_VELOCITYROAM:
+ txt_flightmode = txt_velocityroam;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_HOMELEASH:
+ txt_flightmode = txt_homeleash;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_ABSOLUTEPOSITION:
+ txt_flightmode = txt_absoluteposition;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_RETURNTOBASE:
+ txt_flightmode = txt_returntobase;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_LAND:
+ txt_flightmode = txt_land;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER:
+ txt_flightmode = txt_pathplanner;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_POI:
+ txt_flightmode = txt_poi;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_AUTOCRUISE:
+ txt_flightmode = txt_autocruise;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_AUTOTAKEOFF:
+ txt_flightmode = txt_autotakeoff;
+ break;
+ case FLIGHTSTATUS_FLIGHTMODE_AUTOTUNE:
+ txt_flightmode = txt_autotune;
+ break;
+ default:
+ txt_flightmode = txt_unknown;
+ }
+
+ const char *txt_armstate;
+ switch (telestate->FlightStatus.Armed) {
+ case FLIGHTSTATUS_ARMED_DISARMED:
+ txt_armstate = txt_disarmed;
+ break;
+ case FLIGHTSTATUS_ARMED_ARMING:
+ txt_armstate = txt_arming;
+ break;
+ case FLIGHTSTATUS_ARMED_ARMED:
+ txt_armstate = txt_armed;
+ break;
+ default:
+ txt_armstate = txt_unknown;
+ }
+
+ snprintf(telestate->statusline, sizeof(telestate->statusline), "%12s,%8s", txt_flightmode, txt_armstate);
+}
+
+/**
+ * generate warning beeps or spoken announcements
+ */
+uint8_t generate_warning()
+{
+ // set warning tone with hardcoded priority
+ if ((telestate->Settings.Warning.MinSpeed == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MinSpeed > telestate->GPS.Groundspeed * MS_TO_KMH)) {
+ return HOTT_TONE_A; // maximum speed
+ }
+ if ((telestate->Settings.Warning.NegDifference2 == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.NegDifference2 > telestate->climbrate3s)) {
+ return HOTT_TONE_B; // sink rate 3s
+ }
+ if ((telestate->Settings.Warning.NegDifference1 == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.NegDifference1 > telestate->climbrate1s)) {
+ return HOTT_TONE_C; // sink rate 1s
+ }
+ if ((telestate->Settings.Warning.MaxDistance == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxDistance < telestate->homedistance)) {
+ return HOTT_TONE_D; // maximum distance
+ }
+ if ((telestate->Settings.Warning.MinSensor1Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MinSensor1Temp > telestate->Gyro.temperature)) {
+ return HOTT_TONE_F; // minimum temperature sensor 1
+ }
+ if ((telestate->Settings.Warning.MinSensor2Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MinSensor2Temp > telestate->Baro.Temperature)) {
+ return HOTT_TONE_G; // minimum temperature sensor 2
+ }
+ if ((telestate->Settings.Warning.MaxSensor1Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxSensor1Temp < telestate->Gyro.temperature)) {
+ return HOTT_TONE_H; // maximum temperature sensor 1
+ }
+ if ((telestate->Settings.Warning.MaxSensor2Temp == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxSensor2Temp < telestate->Baro.Temperature)) {
+ return HOTT_TONE_I; // maximum temperature sensor 2
+ }
+ if ((telestate->Settings.Warning.MaxSpeed == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxSpeed < telestate->GPS.Groundspeed * MS_TO_KMH)) {
+ return HOTT_TONE_L; // maximum speed
+ }
+ if ((telestate->Settings.Warning.PosDifference2 == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.PosDifference2 > telestate->climbrate3s)) {
+ return HOTT_TONE_M; // climb rate 3s
+ }
+ if ((telestate->Settings.Warning.PosDifference1 == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.PosDifference1 > telestate->climbrate1s)) {
+ return HOTT_TONE_N; // climb rate 1s
+ }
+ if ((telestate->Settings.Warning.MinHeight == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MinHeight > telestate->altitude)) {
+ return HOTT_TONE_O; // minimum height
+ }
+ if ((telestate->Settings.Warning.MinPowerVoltage == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MinPowerVoltage > telestate->Battery.Voltage)) {
+ return HOTT_TONE_P; // minimum input voltage
+ }
+ if ((telestate->Settings.Warning.MaxUsedCapacity == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxUsedCapacity < telestate->Battery.ConsumedEnergy)) {
+ return HOTT_TONE_V; // capacity
+ }
+ if ((telestate->Settings.Warning.MaxCurrent == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxCurrent < telestate->Battery.Current)) {
+ return HOTT_TONE_W; // maximum current
+ }
+ if ((telestate->Settings.Warning.MaxPowerVoltage == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxPowerVoltage < telestate->Battery.Voltage)) {
+ return HOTT_TONE_X; // maximum input voltage
+ }
+ if ((telestate->Settings.Warning.MaxHeight == HOTTBRIDGESETTINGS_WARNING_ENABLED) &&
+ (telestate->Settings.Limit.MaxHeight < telestate->altitude)) {
+ return HOTT_TONE_Z; // maximum height
+ }
+ // altitude beeps when crossing altitude limits at 20,40,60,80,100,200,400,600,800 and 1000 meters
+ if (telestate->Settings.Warning.AltitudeBeep == HOTTBRIDGESETTINGS_WARNING_ENABLED) {
+ // update altitude when checked for beeps
+ float last = telestate->altitude_last;
+ float actual = telestate->altitude;
+ telestate->altitude_last = telestate->altitude;
+ if (((last < 20) && (actual >= 20)) || ((last > 20) && (actual <= 20))) {
+ return HOTT_TONE_20M;
+ }
+ if (((last < 40) && (actual >= 40)) || ((last > 40) && (actual <= 40))) {
+ return HOTT_TONE_40M;
+ }
+ if (((last < 60) && (actual >= 60)) || ((last > 60) && (actual <= 60))) {
+ return HOTT_TONE_60M;
+ }
+ if (((last < 80) && (actual >= 80)) || ((last > 80) && (actual <= 80))) {
+ return HOTT_TONE_80M;
+ }
+ if (((last < 100) && (actual >= 100)) || ((last > 100) && (actual <= 100))) {
+ return HOTT_TONE_100M;
+ }
+ if (((last < 200) && (actual >= 200)) || ((last > 200) && (actual <= 200))) {
+ return HOTT_TONE_200M;
+ }
+ if (((last < 400) && (actual >= 400)) || ((last > 400) && (actual <= 400))) {
+ return HOTT_TONE_400M;
+ }
+ if (((last < 600) && (actual >= 600)) || ((last > 600) && (actual <= 600))) {
+ return HOTT_TONE_600M;
+ }
+ if (((last < 800) && (actual >= 800)) || ((last > 800) && (actual <= 800))) {
+ return HOTT_TONE_800M;
+ }
+ if (((last < 1000) && (actual >= 1000)) || ((last > 1000) && (actual <= 1000))) {
+ return HOTT_TONE_1000M;
+ }
+ }
+
+ // there is no warning
+ return 0;
+}
+
+/**
+ * calculate checksum of data buffer
+ */
+uint8_t calc_checksum(uint8_t *data, uint16_t size)
+{
+ uint16_t sum = 0;
+
+ for (int i = 0; i < size; i++) {
+ sum += data[i];
+ }
+ return sum;
+}
+
+/**
+ * scale float value with scale and offset to unsigned byte
+ */
+uint8_t scale_float2uint8(float value, float scale, float offset)
+{
+ uint16_t temp = (uint16_t)roundf(value * scale + offset);
+ uint8_t result;
+
+ result = (uint8_t)temp & 0xff;
+ return result;
+}
+
+/**
+ * scale float value with scale and offset to signed byte (int8_t)
+ */
+int8_t scale_float2int8(float value, float scale, float offset)
+{
+ int8_t result = (int8_t)roundf(value * scale + offset);
+
+ return result;
+}
+
+/**
+ * scale float value with scale and offset to word
+ */
+uword_t scale_float2uword(float value, float scale, float offset)
+{
+ uint16_t temp = (uint16_t)roundf(value * scale + offset);
+ uword_t result;
+
+ result.l = (uint8_t)temp & 0xff;
+ result.h = (uint8_t)(temp >> 8) & 0xff;
+ return result;
+}
+
+/**
+ * convert dword gps value into HoTT gps format and write result to given pointers
+ */
+void convert_long2gps(int32_t value, uint8_t *dir, uword_t *min, uword_t *sec)
+{
+ // convert gps decigrad value into degrees, minutes and seconds
+ uword_t temp;
+ uint32_t absvalue = abs(value);
+ uint16_t degrees = (absvalue / 10000000);
+ uint32_t seconds = (absvalue - degrees * 10000000) * 6;
+ uint16_t minutes = seconds / 1000000;
+
+ seconds %= 1000000;
+ seconds = seconds / 100;
+ uint16_t degmin = degrees * 100 + minutes;
+ // write results
+ *dir = (value < 0) ? 1 : 0;
+ temp.l = (uint8_t)degmin & 0xff;
+ temp.h = (uint8_t)(degmin >> 8) & 0xff;
+ *min = temp;
+ temp.l = (uint8_t)seconds & 0xff;
+ temp.h = (uint8_t)(seconds >> 8) & 0xff;
+ *sec = temp;
+}
+
+#endif // PIOS_INCLUDE_HOTT_BRIDGE
+/**
+ * @}
+ * @}
+ */
diff --git a/flight/pios/common/pios_com.c b/flight/pios/common/pios_com.c
index d13a7ca89..a1bfde67a 100644
--- a/flight/pios/common/pios_com.c
+++ b/flight/pios/common/pios_com.c
@@ -282,6 +282,30 @@ int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud)
return 0;
}
+/**
+ * Change the port type to halfduplex (shared rx/tx medium)
+ * \param[in] port COM port
+ * \param[in] halfduplex enabled
+ * \return -1 if port not available
+ * \return 0 on success
+ */
+int32_t PIOS_COM_SetHalfDuplex(uint32_t com_id, bool halfduplex)
+{
+ struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id;
+
+ if (!PIOS_COM_validate(com_dev)) {
+ /* Undefined COM port for this board (see pios_board.c) */
+ return -1;
+ }
+
+ /* Invoke the driver function if it exists */
+ if (com_dev->driver->set_halfduplex) {
+ com_dev->driver->set_halfduplex(com_dev->lower_id, halfduplex);
+ }
+
+ return 0;
+}
+
int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode)
{
struct pios_com_dev *com_dev = (struct pios_com_dev *)com_id;
diff --git a/flight/pios/inc/pios_com.h b/flight/pios/inc/pios_com.h
index 9364e5942..f576b346f 100644
--- a/flight/pios/inc/pios_com.h
+++ b/flight/pios/inc/pios_com.h
@@ -72,6 +72,7 @@ enum PIOS_COM_Mode {
struct pios_com_driver {
void (*init)(uint32_t id);
void (*set_baud)(uint32_t id, uint32_t baud);
+ void (*set_halfduplex)(uint32_t id, bool halfduplex);
void (*set_config)(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode);
void (*set_ctrl_line)(uint32_t id, uint32_t mask, uint32_t state);
void (*tx_start)(uint32_t id, uint16_t tx_bytes_avail);
@@ -91,6 +92,7 @@ struct pios_com_driver {
/* Public Functions */
extern int32_t PIOS_COM_Init(uint32_t *com_id, const struct pios_com_driver *driver, uint32_t lower_id, uint8_t *rx_buffer, uint16_t rx_buffer_len, uint8_t *tx_buffer, uint16_t tx_buffer_len);
extern int32_t PIOS_COM_ChangeBaud(uint32_t com_id, uint32_t baud);
+extern int32_t PIOS_COM_SetHalfDuplex(uint32_t com_id, bool halfduplex);
extern int32_t PIOS_COM_ChangeConfig(uint32_t com_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode);
extern int32_t PIOS_COM_SetCtrlLine(uint32_t com_id, uint32_t mask, uint32_t state);
extern int32_t PIOS_COM_RegisterCtrlLineCallback(uint32_t usart_id, pios_com_callback_ctrl_line ctrl_line_cb, uint32_t context);
diff --git a/flight/pios/stm32f4xx/pios_usart.c b/flight/pios/stm32f4xx/pios_usart.c
index 01d790963..e594f55e0 100644
--- a/flight/pios/stm32f4xx/pios_usart.c
+++ b/flight/pios/stm32f4xx/pios_usart.c
@@ -41,6 +41,7 @@
/* Provide a COM driver */
static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud);
+static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex);
static void PIOS_USART_ChangeConfig(uint32_t usart_id, enum PIOS_COM_Word_Length word_len, enum PIOS_COM_StopBits stop_bits, enum PIOS_COM_Parity parity, uint32_t baud_rate, enum PIOS_COM_Mode mode);
static void PIOS_USART_SetCtrlLine(uint32_t usart_id, uint32_t mask, uint32_t state);
static void PIOS_USART_RegisterRxCallback(uint32_t usart_id, pios_com_callback rx_in_cb, uint32_t context);
@@ -49,13 +50,14 @@ static void PIOS_USART_TxStart(uint32_t usart_id, uint16_t tx_bytes_avail);
static void PIOS_USART_RxStart(uint32_t usart_id, uint16_t rx_bytes_avail);
const struct pios_com_driver pios_usart_com_driver = {
- .set_baud = PIOS_USART_ChangeBaud,
- .set_config = PIOS_USART_ChangeConfig,
- .set_ctrl_line = PIOS_USART_SetCtrlLine,
- .tx_start = PIOS_USART_TxStart,
- .rx_start = PIOS_USART_RxStart,
- .bind_tx_cb = PIOS_USART_RegisterTxCallback,
- .bind_rx_cb = PIOS_USART_RegisterRxCallback,
+ .set_baud = PIOS_USART_ChangeBaud,
+ .set_halfduplex = PIOS_USART_SetHalfDuplex,
+ .set_config = PIOS_USART_ChangeConfig,
+ .set_ctrl_line = PIOS_USART_SetCtrlLine,
+ .tx_start = PIOS_USART_TxStart,
+ .rx_start = PIOS_USART_RxStart,
+ .bind_tx_cb = PIOS_USART_RegisterTxCallback,
+ .bind_rx_cb = PIOS_USART_RegisterRxCallback,
};
enum pios_usart_dev_magic {
@@ -286,6 +288,22 @@ static void PIOS_USART_ChangeBaud(uint32_t usart_id, uint32_t baud)
USART_Init(usart_dev->cfg->regs, &usart_dev->init);
}
+/**
+ * Sets the USART peripheral into half duplex mode
+ * \param[in] usart_id USART name (GPS, TELEM, AUX)
+ * \param[in] bool wether to set half duplex or not
+ */
+static void PIOS_USART_SetHalfDuplex(uint32_t usart_id, bool halfduplex)
+{
+ struct pios_usart_dev *usart_dev = (struct pios_usart_dev *)usart_id;
+
+ bool valid = PIOS_USART_validate(usart_dev);
+
+ PIOS_Assert(valid);
+
+ USART_HalfDuplexCmd(usart_dev->cfg->regs, halfduplex ? ENABLE : DISABLE);
+}
+
/**
* Changes configuration of the USART peripheral without re-initialising.
* \param[in] usart_id USART name (GPS, TELEM, AUX)
diff --git a/flight/targets/boards/revolution/firmware/Makefile b/flight/targets/boards/revolution/firmware/Makefile
index 5ee49d1a2..6a51ba5a2 100644
--- a/flight/targets/boards/revolution/firmware/Makefile
+++ b/flight/targets/boards/revolution/firmware/Makefile
@@ -55,6 +55,7 @@ MODULES += Notify
OPTMODULES += AutoTune
OPTMODULES += ComUsbBridge
+OPTMODULES += UAVOHottBridge
OPTMODULES += UAVOMSPBridge
OPTMODULES += UAVOMavlinkBridge
diff --git a/flight/targets/boards/revolution/firmware/UAVObjects.inc b/flight/targets/boards/revolution/firmware/UAVObjects.inc
index 5774e7ae4..84195dee9 100644
--- a/flight/targets/boards/revolution/firmware/UAVObjects.inc
+++ b/flight/targets/boards/revolution/firmware/UAVObjects.inc
@@ -126,6 +126,8 @@ UAVOBJSRCFILENAMES += poilearnsettings
UAVOBJSRCFILENAMES += mpugyroaccelsettings
UAVOBJSRCFILENAMES += txpidsettings
UAVOBJSRCFILENAMES += txpidstatus
+UAVOBJSRCFILENAMES += hottbridgesettings
+UAVOBJSRCFILENAMES += hottbridgestatus
UAVOBJSRCFILENAMES += takeofflocation
UAVOBJSRCFILENAMES += perfcounter
UAVOBJSRCFILENAMES += systemidentsettings
diff --git a/flight/targets/boards/revolution/firmware/inc/pios_config.h b/flight/targets/boards/revolution/firmware/inc/pios_config.h
index efe32a4be..c50d8c598 100644
--- a/flight/targets/boards/revolution/firmware/inc/pios_config.h
+++ b/flight/targets/boards/revolution/firmware/inc/pios_config.h
@@ -119,6 +119,7 @@
#define PIOS_INCLUDE_LED
#define PIOS_INCLUDE_IAP
#define PIOS_INCLUDE_SERVO
+#define PIOS_INCLUDE_HOTT_BRIDGE
/* #define PIOS_INCLUDE_I2C_ESC */
/* #define PIOS_INCLUDE_OVERO */
/* #define PIOS_OVERO_SPI */
diff --git a/flight/targets/boards/revolution/firmware/pios_board.c b/flight/targets/boards/revolution/firmware/pios_board.c
index 9c42aa0ef..e5294dc3e 100644
--- a/flight/targets/boards/revolution/firmware/pios_board.c
+++ b/flight/targets/boards/revolution/firmware/pios_board.c
@@ -251,6 +251,9 @@ uint32_t pios_rcvr_group_map[MANUALCONTROLSETTINGS_CHANNELGROUPS_NONE];
#define PIOS_COM_BRIDGE_RX_BUF_LEN 65
#define PIOS_COM_BRIDGE_TX_BUF_LEN 12
+#define PIOS_COM_HOTT_RX_BUF_LEN 512
+#define PIOS_COM_HOTT_TX_BUF_LEN 512
+
#define PIOS_COM_RFM22B_RF_RX_BUF_LEN 512
#define PIOS_COM_RFM22B_RF_TX_BUF_LEN 512
@@ -272,6 +275,7 @@ uint32_t pios_com_telem_usb_id = 0;
uint32_t pios_com_telem_rf_id = 0;
uint32_t pios_com_rf_id = 0;
uint32_t pios_com_bridge_id = 0;
+uint32_t pios_com_hott_id = 0;
uint32_t pios_com_overo_id = 0;
uint32_t pios_com_hkosd_id = 0;
uint32_t pios_com_vcp_id = 0;
@@ -628,6 +632,9 @@ void PIOS_Board_Init(void)
}
#endif /* PIOS_INCLUDE_HOTT */
break;
+ case HWSETTINGS_RM_FLEXIPORT_HOTTTELEMETRY:
+ PIOS_Board_configure_com(&pios_usart_hott_flexi_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id);
+ break;
case HWSETTINGS_RM_FLEXIPORT_EXBUS:
#if defined(PIOS_INCLUDE_EXBUS)
@@ -840,6 +847,9 @@ void PIOS_Board_Init(void)
}
#endif /* PIOS_INCLUDE_DEBUG_CONSOLE */
break;
+ case HWSETTINGS_RM_MAINPORT_HOTTTELEMETRY:
+ PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id);
+ break;
case HWSETTINGS_RM_MAINPORT_COMBRIDGE:
PIOS_Board_configure_com(&pios_usart_main_cfg, PIOS_COM_BRIDGE_RX_BUF_LEN, PIOS_COM_BRIDGE_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_bridge_id);
break;
@@ -1044,6 +1054,7 @@ void PIOS_Board_Init(void)
case HWSETTINGS_RM_RCVRPORT_PPMMSP:
case HWSETTINGS_RM_RCVRPORT_PPMMAVLINK:
case HWSETTINGS_RM_RCVRPORT_PPMGPS:
+ case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY:
#if defined(PIOS_INCLUDE_PPM)
PIOS_Board_configure_ppm(&pios_ppm_cfg);
@@ -1093,6 +1104,10 @@ void PIOS_Board_Init(void)
case HWSETTINGS_RM_RCVRPORT_PPMGPS:
PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_GPS_RX_BUF_LEN, PIOS_COM_GPS_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_gps_id);
break;
+ case HWSETTINGS_RM_RCVRPORT_HOTTTELEMETRY:
+ case HWSETTINGS_RM_RCVRPORT_PPMHOTTTELEMETRY:
+ PIOS_Board_configure_com(&pios_usart_rcvrport_cfg, PIOS_COM_HOTT_RX_BUF_LEN, PIOS_COM_HOTT_TX_BUF_LEN, &pios_usart_com_driver, &pios_com_hott_id);
+ break;
case HWSETTINGS_RM_RCVRPORT_IBUS:
#if defined(PIOS_INCLUDE_IBUS)
PIOS_Board_configure_ibus(&pios_usart_ibus_rcvr_cfg);
diff --git a/flight/targets/boards/revolution/pios_board.h b/flight/targets/boards/revolution/pios_board.h
index a97fdbd67..fb0f469e8 100644
--- a/flight/targets/boards/revolution/pios_board.h
+++ b/flight/targets/boards/revolution/pios_board.h
@@ -146,6 +146,7 @@ extern uint32_t pios_com_rf_id;
extern uint32_t pios_com_gps_id;
extern uint32_t pios_com_telem_usb_id;
extern uint32_t pios_com_bridge_id;
+extern uint32_t pios_com_hott_id;
extern uint32_t pios_com_vcp_id;
extern uint32_t pios_com_hkosd_id;
extern uint32_t pios_com_msp_id;
@@ -156,6 +157,7 @@ extern uint32_t pios_com_mavlink_id;
#define PIOS_COM_TELEM_RF (pios_com_telem_rf_id)
#define PIOS_COM_RF (pios_com_rf_id)
#define PIOS_COM_BRIDGE (pios_com_bridge_id)
+#define PIOS_COM_HOTT (pios_com_hott_id)
#define PIOS_COM_VCP (pios_com_vcp_id)
#define PIOS_COM_OSDHK (pios_com_hkosd_id)
#define PIOS_COM_MSP (pios_com_msp_id)
diff --git a/ground/gcs/src/plugins/uavobjects/uavobjects.pro b/ground/gcs/src/plugins/uavobjects/uavobjects.pro
index 942e79742..46236e484 100644
--- a/ground/gcs/src/plugins/uavobjects/uavobjects.pro
+++ b/ground/gcs/src/plugins/uavobjects/uavobjects.pro
@@ -94,6 +94,8 @@ UAVOBJS = \
$${UAVOBJ_XML_DIR}/gyrosensor.xml \
$${UAVOBJ_XML_DIR}/gyrostate.xml \
$${UAVOBJ_XML_DIR}/homelocation.xml \
+ $${UAVOBJ_XML_DIR}/hottbridgesettings.xml \
+ $${UAVOBJ_XML_DIR}/hottbridgestatus.xml \
$${UAVOBJ_XML_DIR}/hwsettings.xml \
$${UAVOBJ_XML_DIR}/i2cstats.xml \
$${UAVOBJ_XML_DIR}/magsensor.xml \
diff --git a/shared/uavobjectdefinition/hottbridgesettings.xml b/shared/uavobjectdefinition/hottbridgesettings.xml
new file mode 100644
index 000000000..81964dbc5
--- /dev/null
+++ b/shared/uavobjectdefinition/hottbridgesettings.xml
@@ -0,0 +1,82 @@
+
+
+
diff --git a/shared/uavobjectdefinition/hottbridgestatus.xml b/shared/uavobjectdefinition/hottbridgestatus.xml
new file mode 100644
index 000000000..89e724999
--- /dev/null
+++ b/shared/uavobjectdefinition/hottbridgestatus.xml
@@ -0,0 +1,15 @@
+
+
+
diff --git a/shared/uavobjectdefinition/hwsettings.xml b/shared/uavobjectdefinition/hwsettings.xml
index f0dfe1950..fed486c90 100644
--- a/shared/uavobjectdefinition/hwsettings.xml
+++ b/shared/uavobjectdefinition/hwsettings.xml
@@ -11,11 +11,11 @@
-
-
-
+ limits="%0905NE:PPM+PWM:PPM+Telemetry:PPM+DebugConsole:PPM+ComBridge:PPM+MSP:PPM+MAVLink:PPM+GPS:PPM+HoTT Telemetry:Telemetry:DebugConsole:ComBridge:MSP:MAVLink:GPS:HoTT Telemetry:IBus;"/>
+
+
diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml
index 1d7a2f4f1..57a98354f 100644
--- a/shared/uavobjectdefinition/taskinfo.xml
+++ b/shared/uavobjectdefinition/taskinfo.xml
@@ -31,6 +31,7 @@
GPS
OSDGen
+ UAVOHoTTBridge
UAVOMSPBridge
AutoTune
UAVOMAVLinkBridge
@@ -66,6 +67,7 @@
GPS
OSDGen
+ UAVOHoTTBridge
UAVOMSPBridge
AutoTune
UAVOMAVLinkBridge
@@ -105,6 +107,7 @@
GPS
OSDGen
+ UAVOHoTTBridge
UAVOMSPBridge
AutoTune
UAVOMAVLinkBridge