dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
UAVOFrSKYSPortBridge.c
Go to the documentation of this file.
1 
20 /*
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License as published by
23  * the Free Software Foundation; either version 3 of the License, or
24  * (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful, but
27  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
28  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29  * for more details.
30  *
31  * You should have received a copy of the GNU General Public License along
32  * with this program; if not, see <http://www.gnu.org/licenses/>
33  */
34 
35 #include "frsky_packing.h"
36 #include "pios_thread.h"
37 #include "pios_modules.h"
38 
39 #include "baroaltitude.h"
40 #include "flightbatterysettings.h"
41 #include "flightbatterystate.h"
42 #include "gpsposition.h"
43 #include "modulesettings.h"
44 
45 #if defined(PIOS_INCLUDE_FRSKY_SPORT_TELEMETRY)
46 
47 #define FRSKY_POLL_REQUEST 0x7e
48 #define FRSKY_MINIMUM_POLL_INTERVAL 10000
49 
50 enum frsky_state {
51  FRSKY_STATE_WAIT_POLL_REQUEST,
52  FRSKY_STATE_WAIT_SENSOR_ID,
53  FRSKY_STATE_WAIT_TX_DONE,
54 };
55 
56 // Set of objects sent by this module
57 static const struct frsky_value_item frsky_value_items[] = {
58  {FRSKY_GPS_COURSE_ID, 100, frsky_encode_gps_course, 0}, // attitude yaw estimate
59  {FRSKY_ALT_ID, 100, frsky_encode_altitude, 0}, // altitude estimate
60  {FRSKY_VARIO_ID, 100, frsky_encode_vario, 0}, // vertical speed
61  {FRSKY_CURR_ID, 300, frsky_encode_current, 0}, // battery current
62  {FRSKY_CELLS_ID, 850, frsky_encode_cells, 0}, // battery cells 1-2
63  {FRSKY_CELLS_ID, 850, frsky_encode_cells, 1}, // battery cells 3-4
64  {FRSKY_CELLS_ID, 850, frsky_encode_cells, 2}, // battery cells 5-6
65  {FRSKY_CELLS_ID, 850, frsky_encode_cells, 3}, // battery cells 7-8
66  {FRSKY_CELLS_ID, 850, frsky_encode_cells, 4}, // battery cells 9-10
67  {FRSKY_CELLS_ID, 850, frsky_encode_cells, 5}, // battery cells 11-12
68  {FRSKY_T1_ID, 2000, frsky_encode_t1, 0}, // baro temperature
69  {FRSKY_T2_ID, 1500, frsky_encode_t2, 0}, // encodes GPS status!
70  {FRSKY_FUEL_ID, 600, frsky_encode_fuel, 0}, // consumed battery energy
71  {FRSKY_ACCX_ID, 100, frsky_encode_acc, 0}, // accX
72  {FRSKY_ACCY_ID, 100, frsky_encode_acc, 1}, // accY
73  {FRSKY_ACCZ_ID, 100, frsky_encode_acc, 2}, // accZ
74  {FRSKY_GPS_LON_LAT_ID, 100, frsky_encode_gps_coord, 0}, // lattitude
75  {FRSKY_GPS_LON_LAT_ID, 100, frsky_encode_gps_coord, 1}, // longitude
76  {FRSKY_GPS_ALT_ID, 750, frsky_encode_gps_alt, 0}, // gps altitude
77  {FRSKY_GPS_SPEED_ID, 200, frsky_encode_gps_speed, 0}, // gps speed
78  {FRSKY_GPS_TIME_ID, 8000, frsky_encode_gps_time, 0}, // gps date
79  {FRSKY_GPS_TIME_ID, 2000, frsky_encode_gps_time, 1}, // gps time
80  {FRSKY_RPM_ID, 1500, frsky_encode_rpm, 0}, // encodes flight status!
81  {FRSKY_AIR_SPEED_ID, 100, frsky_encode_airspeed, 0}, // airspeed
82 };
83 
84 struct frsky_sport_telemetry {
85  enum frsky_state state;
86  int32_t scheduled_item;
87  uint32_t last_poll_time;
88  uint8_t ignore_rx_chars;
89  uintptr_t com;
91  uint32_t item_last_triggered[NELEMENTS(frsky_value_items)];
92 };
93 
94 static const uint8_t frsky_sensor_ids[] = {0x1b};
95 
96 #define FRSKY_SPORT_BAUDRATE 57600
97 
98 #if defined(PIOS_FRSKY_SPORT_TELEMETRY_STACK_SIZE)
99 #define STACK_SIZE_BYTES PIOS_FRSKY_SPORT_TELEMETRY_STACK_SIZE
100 #else
101 #define STACK_SIZE_BYTES 672
102 #endif
103 #define TASK_PRIORITY PIOS_THREAD_PRIO_LOW
104 
105 static bool module_enabled = false;
106 static struct frsky_sport_telemetry *frsky;
107 static int32_t uavoFrSKYSPortBridgeInitialize(void);
108 static void uavoFrSKYSPortBridgeTask(void *parameters);
109 
114 static void frsky_schedule_next_item(void)
115 {
116  uint32_t i = 0;
117  int32_t max_exp_time = INT32_MIN;
118  int32_t most_exp_item = -1;
119  for (i = 0; i < NELEMENTS(frsky_value_items); i++) {
120  if (frsky_value_items[i].encode_value(&frsky->frsky_settings, 0, true, frsky_value_items[i].fn_arg)) {
121  int32_t exp_time = PIOS_DELAY_GetuSSince(frsky->item_last_triggered[i]) -
122  (frsky_value_items[i].period_ms * 1000);
123  if (exp_time > max_exp_time) {
124  max_exp_time = exp_time;
125  most_exp_item = i;
126  }
127  }
128  }
129  frsky->scheduled_item = most_exp_item;
130 }
135 static bool frsky_send_scheduled_item(void)
136 {
137  int32_t item = frsky->scheduled_item;
138  if ((item >= 0) && (item < NELEMENTS(frsky_value_items))) {
139  frsky->item_last_triggered[item] = PIOS_DELAY_GetuS();
140  uint32_t value = 0;
141  if (frsky_value_items[item].encode_value(&frsky->frsky_settings, &value, false,
142  frsky_value_items[item].fn_arg)) {
143  frsky->ignore_rx_chars += frsky_send_frame(frsky->com, (uint16_t)(frsky_value_items[item].id), value, false);
144  return true;
145  }
146  }
147 
148  return false;
149 }
150 
155 static void frsky_receive_byte(uint8_t b)
156 {
157  uint32_t i = 0;
158  switch (frsky->state) {
159  case FRSKY_STATE_WAIT_TX_DONE:
160  // because RX and TX are connected, we need to ignore bytes
161  // transmited by us
162  if (--frsky->ignore_rx_chars == 0)
163  frsky->state = FRSKY_STATE_WAIT_POLL_REQUEST;
164  break;
165 
166  case FRSKY_STATE_WAIT_POLL_REQUEST:
167  if (b == FRSKY_POLL_REQUEST) {
168  // X8R is polling us every 13ms
169  if (PIOS_DELAY_GetuSSince(frsky->last_poll_time) > FRSKY_MINIMUM_POLL_INTERVAL) {
170  frsky->last_poll_time = PIOS_DELAY_GetuS();
171  frsky->state = FRSKY_STATE_WAIT_SENSOR_ID;
172  }
173  }
174  break;
175 
176  case FRSKY_STATE_WAIT_SENSOR_ID:
177  frsky->state = FRSKY_STATE_WAIT_POLL_REQUEST;
178  for (i = 0; i < sizeof(frsky_sensor_ids); i++) {
179  if (frsky_sensor_ids[i] == b) {
180  // get GPSPositionData once here to be more efficient, since
181  // GPS position data are very often used by encode() handlers
182  if (GPSPositionHandle() != NULL)
183  GPSPositionGet(&frsky->frsky_settings.gps_position);
184  // send item previously scheduled
185  if (frsky_send_scheduled_item() && frsky->ignore_rx_chars)
186  frsky->state = FRSKY_STATE_WAIT_TX_DONE;
187  // schedule item for next poll turn
188  frsky_schedule_next_item();
189  break;
190  }
191  }
192  break;
193  }
194 }
195 
200 static int32_t uavoFrSKYSPortBridgeStart(void)
201 {
202  if (!module_enabled)
203  return -1;
204 
205  if (FlightBatterySettingsHandle() != NULL
206  && FlightBatteryStateHandle() != NULL) {
207  uint8_t currentPin;
208  FlightBatterySettingsCurrentPinGet(&currentPin);
209  if (currentPin != FLIGHTBATTERYSETTINGS_CURRENTPIN_NONE)
210  frsky->frsky_settings.use_current_sensor = true;
211  FlightBatterySettingsGet(&frsky->frsky_settings.battery_settings);
212  frsky->frsky_settings.batt_cell_count = frsky->frsky_settings.battery_settings.NbCells;
213  }
214  if (BaroAltitudeHandle() != NULL
216  frsky->frsky_settings.use_baro_sensor = true;
217 
218  struct pios_thread *task;
219  task = PIOS_Thread_Create(
220  uavoFrSKYSPortBridgeTask, "uavoFrSKYSPortBridge",
222  TaskMonitorAdd(TASKINFO_RUNNING_UAVOFRSKYSPORTBRIDGE,
223  task);
224 
225  return 0;
226 }
227 
232 static int32_t uavoFrSKYSPortBridgeInitialize(void)
233 {
234  uintptr_t sport_com = PIOS_COM_FRSKY_SPORT;
235 
237  frsky = PIOS_malloc(sizeof(struct frsky_sport_telemetry));
238  if (frsky != NULL) {
239  memset(frsky, 0x00, sizeof(struct frsky_sport_telemetry));
240 
241  frsky->frsky_settings.use_current_sensor = false;
242  frsky->frsky_settings.batt_cell_count = 0;
243  frsky->frsky_settings.use_baro_sensor = false;
244  frsky->state = FRSKY_STATE_WAIT_POLL_REQUEST;
245  frsky->last_poll_time = PIOS_DELAY_GetuS();
246  frsky->ignore_rx_chars = 0;
247  frsky->scheduled_item = -1;
248  frsky->com = sport_com;
249 
250  uint8_t i;
251  for (i = 0; i < NELEMENTS(frsky_value_items); i++)
252  frsky->item_last_triggered[i] = PIOS_DELAY_GetuS();
253  PIOS_COM_ChangeBaud(frsky->com, FRSKY_SPORT_BAUDRATE);
254  module_enabled = true;
255  return 0;
256  }
257  }
258 
259  return -1;
260 }
261 MODULE_INITCALL(uavoFrSKYSPortBridgeInitialize, uavoFrSKYSPortBridgeStart)
262 
263 
267 static void uavoFrSKYSPortBridgeTask(void *parameters)
268 {
269  while (1) {
270  uint8_t b = 0;
271  uint16_t count = PIOS_COM_ReceiveBuffer(frsky->com, &b, 1, PIOS_QUEUE_TIMEOUT_MAX);
272  if (count)
273  frsky_receive_byte(b);
274  }
275 }
276 
277 #endif //PIOS_INCLUDE_FRSKY_SPORT_TELEMETRY
278 
Packs UAVObjects into FrSKY Smart Port frames.
bool frsky_encode_vario(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
uint32_t PIOS_DELAY_GetuS()
Query the Delay timer for the current uS.
Definition: pios_delay.c:173
bool frsky_encode_fuel(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
const uint8_t count
Definition: panel.c:515
bool frsky_encode_airspeed(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
bool frsky_encode_gps_alt(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
#define NELEMENTS(x)
Definition: pios.h:192
bool frsky_encode_gps_time(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
bool PIOS_Modules_IsEnabled(enum pios_modules module)
Definition: pios_modules.c:41
bool frsky_encode_acc(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
#define STACK_SIZE_BYTES
Definition: actuator.c:62
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool frsky_encode_current(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
bool frsky_encode_rpm(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
bool module_enabled
uint32_t PIOS_DELAY_GetuSSince(uint32_t t)
Calculate time in microseconds since a previous time.
Definition: pios_delay.c:183
bool frsky_encode_gps_coord(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
#define TASK_PRIORITY
Definition: actuator.c:65
bool frsky_encode_t2(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
uint16_t period_ms
Definition: frsky_packing.h:83
enum frsky_value_id id
Definition: frsky_packing.h:82
bool PIOS_SENSORS_IsRegistered(enum pios_sensor_type type)
Checks if a sensor type is registered with the PIOS_SENSORS interface.
Definition: pios_sensors.c:88
#define PIOS_QUEUE_TIMEOUT_MAX
Definition: pios_queue.h:30
#define MODULE_INITCALL(ifn, sfn)
Definition: pios_initcall.h:67
uint16_t PIOS_COM_ReceiveBuffer(uintptr_t com_id, uint8_t *buf, uint16_t buf_len, uint32_t timeout_ms)
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
static TaskInfoRunningElem task
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
uint8_t i
Definition: msp_messages.h:97
int32_t frsky_send_frame(uintptr_t com, enum frsky_value_id id, uint32_t value, bool send_prelude)
bool frsky_encode_gps_speed(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
bool frsky_encode_cells(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
uint16_t value
Definition: storm32bgc.c:155
bool frsky_encode_t1(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
bool frsky_encode_altitude(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
Definition: frsky_packing.c:62
bool frsky_encode_gps_course(struct frsky_settings *frsky, uint32_t *value, bool test_presence_only, uint32_t arg)
Definition: frsky_packing.c:85
#define PIOS_COM_FRSKY_SPORT
Definition: pios_board.h:121
int32_t PIOS_COM_ChangeBaud(uintptr_t com_id, uint32_t baud)
enum arena_state state