dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
UAVOFrSKYSensorHubBridge.c
Go to the documentation of this file.
1 
15 /*
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24  * for more details.
25  *
26  * You should have received a copy of the GNU General Public License along
27  * with this program; if not, see <http://www.gnu.org/licenses/>
28  *
29  * Additional note on redistribution: The copyright and license notices above
30  * must be maintained in each individual source file that is a derivative work
31  * of this source file; otherwise redistribution is prohibited.
32  */
33 
34 // ****************
35 #include "pios.h"
36 #include "openpilot.h"
37 #include "physical_constants.h"
38 #include "modulesettings.h"
39 #include "flightbatterysettings.h"
40 #include "flightbatterystate.h"
41 #include "gpsposition.h"
42 #include "airspeedactual.h"
43 #include "baroaltitude.h"
44 #include "homelocation.h"
45 #include "accels.h"
46 #include "flightstatus.h"
47 #include "nedaccel.h"
48 #include "velocityactual.h"
49 #include "attitudeactual.h"
50 #include "pios_thread.h"
51 #include "pios_modules.h"
52 
53 #if defined(PIOS_INCLUDE_FRSKY_SENSOR_HUB)
54 // ****************
55 // Private functions
56 
57 static void uavoFrSKYSensorHubBridgeTask(void *parameters);
58 
59 static uint16_t frsky_pack_altitude(
60  float altitude,
61  uint8_t *serial_buf);
62 
63 static uint16_t frsky_pack_temperature_01(
64  float temperature_01,
65  uint8_t *serial_buf);
66 
67 static uint16_t frsky_pack_temperature_02(
68  float temperature_02,
69  uint8_t *serial_buf);
70 
71 static uint16_t frsky_pack_accel(
72  float accels_x,
73  float accels_y,
74  float accels_z,
75  uint8_t *serial_buf);
76 
77 static uint16_t frsky_pack_cellvoltage(
78  uint8_t cell,
79  float cell_voltage,
80  uint8_t *serial_buf);
81 
82 static uint16_t frsky_pack_fas(
83  float voltage,
84  float current,
85  uint8_t *serial_buf);
86 
87 static uint16_t frsky_pack_rpm(
88  uint16_t rpm,
89  uint8_t *serial_buf);
90 
91 static uint16_t frsky_pack_gps(
92  float course,
93  int32_t latitude,
94  int32_t longitude,
95  float altitude,
96  float speed,
97  uint8_t *serial_buf);
98 
99 static uint16_t frsky_pack_fuel(
100  float fuel_level,
101  uint8_t *serial_buf);
102 
103 static uint16_t frsky_pack_stop(
104  uint8_t *serial_buf);
105 
106 static int16_t frsky_acceleration_unit(float accel);
107 
108 static void frsky_serialize_value(uint8_t valueid,
109  uint8_t *value,
110  uint8_t *serial_buf,
111  uint8_t *index);
112 
113 static void frsky_write_userdata_byte(uint8_t byte,
114  uint8_t *serial_buf,
115  uint8_t *index);
116 
117 static bool frame_trigger(uint8_t frame_num);
118 // ****************
119 // Private constants
120 
121 #if defined(PIOS_FRSKY_SENSOR_HUB_STACK_SIZE)
122 #define STACK_SIZE_BYTES PIOS_FRSKY_SENSOR_HUB_STACK_SIZE
123 #else
124 #define STACK_SIZE_BYTES 672
125 #endif
126 
127 #define TASK_PRIORITY PIOS_THREAD_PRIO_LOW
128 #define TASK_RATE_HZ 10
129 
130 #define FRSKY_MAX_PACKET_LEN 106
131 #define FRSKY_BAUD_RATE 9600
132 
133 #define FRSKY_FRAME_DATA_HEADER 0x5E
134 #define FRSKY_FRAME_STOP 0x5E
135 
136 enum FRSKY_VALUE_ID {
137  FRSKY_GPS_ALTITUDE_INTEGER = 0x01,
138  FRSKY_GPS_ALTITUDE_DECIMAL = FRSKY_GPS_ALTITUDE_INTEGER + 8,
139  FRSKY_TEMPERATURE_1 = 0x02,
140  FRSKY_RPM = 0x03,
141  FRSKY_FUEL_LEVEL = 0x04,
142  FRSKY_TEMPERATURE_2 = 0x05,
143  FRSKY_VOLTAGE = 0x06,
144  FRSKY_ALTITUDE_INTEGER = 0x10,
145  FRSKY_ALTITUDE_DECIMAL = 0x21,
146  FRSKY_GPS_SPEED_INTEGER = 0x11,
147  FRSKY_GPS_SPEED_DECIMAL = 0x11 + 8,
148  FRSKY_GPS_LONGITUDE_INTEGER = 0x12,
149  FRSKY_GPS_LONGITUDE_DECIMAL = FRSKY_GPS_LONGITUDE_INTEGER + 8,
150  FRSKY_GPS_E_W = 0x1A + 8,
151  FRSKY_GPS_LATITUDE_INTEGER = 0x13,
152  FRSKY_GPS_LATITUDE_DECIMAL = FRSKY_GPS_LATITUDE_INTEGER + 8,
153  FRSKY_GPS_N_S = 0x1B + 8,
154  FRSKY_GPS_COURSE_INTEGER = 0x14,
155  FRSKY_GPS_COURSE_DECIMAL = FRSKY_GPS_COURSE_INTEGER + 8,
156  FRSKY_DATE_MONTH = 0x15,
157  FRSKY_DATE_YEAR = 0x16,
158  FRSKY_HOUR_MINUTE = 0x17,
159  FRSKY_SECOND = 0x18,
160  FRSKY_ACCELERATION_X = 0x24,
161  FRSKY_ACCELERATION_Y = 0x25,
162  FRSKY_ACCELERATION_Z = 0x26,
163  FRSKY_VOLTAGE_AMPERE_SENSOR_INTEGER = 0x3A,
164  FRSKY_VOLTAGE_AMPERE_SENSOR_DECIMAL = 0x3B,
165  FRSKY_CURRENT = 0x28,
166 };
167 
168 enum FRSKY_FRAME {
169  FRSKY_FRAME_VARIO,
170  FRSKY_FRAME_BATTERY,
171  FRSKY_FRAME_GPS
172 };
173 
174 static const uint8_t frsky_rates[] = {
175  [FRSKY_FRAME_VARIO] = 0x05, //5Hz
176  [FRSKY_FRAME_BATTERY] = 0x05, //5Hz
177  [FRSKY_FRAME_GPS] = 0x01 //1Hz
178 };
179 
180 #define MAXSTREAMS sizeof(frsky_rates)
181 
182 
183 // ****************
184 // Private variables
185 
186 static struct {
187  struct pios_thread *task_handle;
188 
189  uint32_t frsky_port;
190 
191  uint8_t frame_ticks[MAXSTREAMS];
192 
193  uint8_t serial_buf[FRSKY_MAX_PACKET_LEN];
194 } *shub_global;
195 
201 static int32_t uavoFrSKYSensorHubBridgeStart(void)
202 {
203  if (shub_global) {
204  // Start tasks
205  shub_global->task_handle = PIOS_Thread_Create(
206  uavoFrSKYSensorHubBridgeTask, "uavoFrSKYSensorHubBridge",
208  TaskMonitorAdd(TASKINFO_RUNNING_UAVOFRSKYSENSORHUBBRIDGE,
209  shub_global->task_handle);
210  return 0;
211  }
212  return -1;
213 }
214 
220 static int32_t uavoFrSKYSensorHubBridgeInitialize(void)
221 {
222  uintptr_t frsky_port = PIOS_COM_FRSKY_SENSOR_HUB;
223 
225  shub_global = PIOS_malloc(sizeof(*shub_global));
226 
227  if (shub_global == 0) {
228  return -1;
229  }
230 
231  shub_global->frsky_port = frsky_port;
232 
233  PIOS_COM_ChangeBaud(frsky_port, FRSKY_BAUD_RATE);
234 
235  for (int x = 0; x < MAXSTREAMS; ++x) {
236  shub_global->frame_ticks[x] =
237  (TASK_RATE_HZ / frsky_rates[x]);
238  }
239 
240  return 0;
241  }
242 
243 
244  return -1;
245 }
246 MODULE_INITCALL(uavoFrSKYSensorHubBridgeInitialize, uavoFrSKYSensorHubBridgeStart)
247 
248 
251 static void uavoFrSKYSensorHubBridgeTask(void *parameters)
252 {
253  FlightBatterySettingsData batSettings;
254  FlightBatteryStateData batState;
255  GPSPositionData gpsPosData;
256  BaroAltitudeData baroAltitude;
257  FlightStatusData flightStatus;
258 
259  float accX = 0, accY = 0, accZ = 0;
260 
261  if (FlightBatterySettingsHandle() != NULL )
262  FlightBatterySettingsGet(&batSettings);
263  else {
264  batSettings.Capacity = 0;
265  batSettings.SensorCalibrationFactor[FLIGHTBATTERYSETTINGS_SENSORCALIBRATIONFACTOR_CURRENT] = 0;
266  batSettings.SensorCalibrationFactor[FLIGHTBATTERYSETTINGS_SENSORCALIBRATIONFACTOR_VOLTAGE] = 0;
267  batSettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] = 0;
268  batSettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] = 0;
269  batSettings.NbCells = 0;
270  batSettings.VoltagePin = FLIGHTBATTERYSETTINGS_VOLTAGEPIN_NONE;
271  batSettings.CurrentPin = FLIGHTBATTERYSETTINGS_CURRENTPIN_NONE;
272  }
273 
274  if (GPSPositionHandle() == NULL ) {
275  gpsPosData.Altitude = 0;
276  gpsPosData.GeoidSeparation = 0;
277  gpsPosData.Groundspeed = 0;
278  gpsPosData.HDOP = 0;
279  gpsPosData.Heading = 0;
280  gpsPosData.Latitude = 0;
281  gpsPosData.Longitude = 0;
282  gpsPosData.PDOP = 0;
283  gpsPosData.Satellites = 0;
284  gpsPosData.Status = 0;
285  gpsPosData.VDOP = 0;
286  }
287 
288  if (FlightBatteryStateHandle() == NULL ) {
289  batState.AvgCurrent = 0;
290  batState.BoardSupplyVoltage = 0;
291  batState.ConsumedEnergy = 0;
292  batState.Current = 0;
293  batState.EstimatedFlightTime = 0;
294  batState.PeakCurrent = 0;
295  batState.Voltage = 0;
296  }
297 
298  uint8_t last_armed = FLIGHTSTATUS_ARMED_DISARMED;
299  float altitude_offset = 0.0f;
300 
301  uint16_t msg_length = 0;
302  uint32_t lastSysTime;
303 
304  // Main task loop
305  lastSysTime = PIOS_Thread_Systime();
306 
307  while (1) {
308  PIOS_Thread_Sleep_Until(&lastSysTime, 1000 / TASK_RATE_HZ);
309 
310  if (frame_trigger(FRSKY_FRAME_VARIO)) {
311  msg_length = 0;
312 
313  uint8_t accelDataSettings;
314  ModuleSettingsFrskyAccelDataGet(&accelDataSettings);
315  switch(accelDataSettings) {
316  case MODULESETTINGS_FRSKYACCELDATA_ACCELS: {
317  if (AccelsHandle() != NULL) {
318  AccelsxGet(&accX);
319  AccelsyGet(&accY);
320  AccelszGet(&accZ);
321  }
322  break;
323  }
324  case MODULESETTINGS_FRSKYACCELDATA_NEDACCELS: {
325  if (NedAccelHandle() != NULL) {
326  NedAccelNorthGet(&accX);
327  NedAccelEastGet(&accY);
328  NedAccelDownGet(&accZ);
329  }
330  break;
331  }
332  case MODULESETTINGS_FRSKYACCELDATA_NEDVELOCITY: {
333  if (VelocityActualHandle() != NULL) {
334  VelocityActualNorthGet(&accX);
335  VelocityActualEastGet(&accY);
336  VelocityActualDownGet(&accZ);
337  accX *= GRAVITY / 10.0f;
338  accY *= GRAVITY / 10.0f;
339  accZ *= GRAVITY / 10.0f;
340  }
341  break;
342  }
343 #endif
345  if (AttitudeActualHandle() != NULL) {
346  AttitudeActualRollGet(&accX);
347  AttitudeActualPitchGet(&accY);
348  AttitudeActualYawGet(&accZ);
349  accX *= GRAVITY / 10.0f;
350  accY *= GRAVITY / 10.0f;
351  accZ *= GRAVITY / 10.0f;
352  }
353  break;
354  }
355  }
356 
357  msg_length += frsky_pack_accel(
358  accX,
359  accY,
360  accZ,
361  shub_global->serial_buf + msg_length);
362 
363  if (BaroAltitudeHandle() != NULL)
364  BaroAltitudeGet(&baroAltitude);
365 
366  FlightStatusGet(&flightStatus);
367 
368  // set altitude offset when arming
369  if ((flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMING) ||
370  ((last_armed != FLIGHTSTATUS_ARMED_ARMED) && (flightStatus.Armed == FLIGHTSTATUS_ARMED_ARMED))) {
371  altitude_offset = baroAltitude.Altitude;
372  }
373  last_armed = flightStatus.Armed;
374 
375  float altitude = baroAltitude.Altitude - altitude_offset;
376  msg_length += frsky_pack_altitude(
377  altitude,
378  shub_global->serial_buf + msg_length);
379 
380  msg_length += frsky_pack_stop(shub_global->serial_buf + msg_length);
381 
382  PIOS_COM_SendBuffer(shub_global->frsky_port,
383  shub_global->serial_buf, msg_length);
384  }
385 
386  if (frame_trigger(FRSKY_FRAME_BATTERY)) {
387  msg_length = 0;
388 
389  if (FlightBatteryStateHandle() != NULL)
390  FlightBatteryStateGet(&batState);
391 
392  float voltage = 0.0f;
393  if (batSettings.VoltagePin != FLIGHTBATTERYSETTINGS_VOLTAGEPIN_NONE)
394  voltage = batState.Voltage;
395 
396  float current = 0.0f;
397  if (batSettings.CurrentPin != FLIGHTBATTERYSETTINGS_CURRENTPIN_NONE)
398  current = batState.Current;
399 
400  // As long as there is no voltage for each cell
401  // all cells will have the same voltage.
402  // Receiver will know number of cells.
403  uint8_t cellCount = batState.DetectedCellCount;
404  if(cellCount)
405  batSettings.NbCells = cellCount;
406 
407  if (batSettings.NbCells > 0) {
408  float cell_v = voltage / batSettings.NbCells;
409  for(uint8_t i = 0; i < batSettings.NbCells; ++i) {
410  msg_length += frsky_pack_cellvoltage(
411  i,
412  cell_v,
413  shub_global->serial_buf + msg_length);
414  }
415  }
416 
417  msg_length += frsky_pack_fas(
418  voltage,
419  current,
420  shub_global->serial_buf + msg_length);
421 
422  if (batSettings.Capacity > 0) {
423  float fuel = 1.0f - batState.ConsumedEnergy / batSettings.Capacity;
424  msg_length += frsky_pack_fuel(
425  fuel,
426  shub_global->serial_buf + msg_length);
427  }
428 
429  msg_length += frsky_pack_stop(shub_global->serial_buf + msg_length);
430 
431  PIOS_COM_SendBuffer(shub_global->frsky_port,
432  shub_global->serial_buf, msg_length);
433  }
434 
435  if (frame_trigger(FRSKY_FRAME_GPS)) {
436  msg_length = 0;
437 
447  FlightStatusData flight_status;
448  FlightStatusGet(&flight_status);
449 
450  uint16_t status = 0;
451  float hdop, vdop;
452 
453  status = (flight_status.Armed == FLIGHTSTATUS_ARMED_ARMED) ? 200 : 100;
454  status += flight_status.FlightMode;
455 
456  msg_length += frsky_pack_rpm(status, shub_global->serial_buf + msg_length);
457 
458  uint8_t hl_set = HOMELOCATION_SET_FALSE;
459 
460  if (GPSPositionHandle() != NULL)
461  GPSPositionGet(&gpsPosData);
462 
463  if (HomeLocationHandle() != NULL)
464  HomeLocationSetGet(&hl_set);
465 
476  switch (gpsPosData.Status) {
477  case GPSPOSITION_STATUS_NOGPS:
478  status = 100;
479  break;
480  case GPSPOSITION_STATUS_NOFIX:
481  status = 200;
482  break;
483  case GPSPOSITION_STATUS_FIX2D:
484  status = 300;
485  break;
486  case GPSPOSITION_STATUS_FIX3D:
487  case GPSPOSITION_STATUS_DIFF3D:
488  if (hl_set == HOMELOCATION_SET_TRUE)
489  status = 500;
490  else
491  status = 400;
492  break;
493  }
494 
495  if (gpsPosData.Satellites > 0)
496  status += gpsPosData.Satellites;
497 
498  msg_length += frsky_pack_temperature_01((float)status, shub_global->serial_buf + msg_length);
499 
506  hdop = gpsPosData.HDOP * 100.0f;
507 
508  if (hdop > 255.0f)
509  hdop = 255.0f;
510 
511  vdop = gpsPosData.VDOP * 100.0f;
512 
513  if (vdop > 255.0f)
514  vdop = 255.0f;
515 
516  msg_length += frsky_pack_temperature_02((vdop * 256 + hdop), shub_global->serial_buf + msg_length);
517 
518  if (gpsPosData.Status == GPSPOSITION_STATUS_FIX2D ||
519  gpsPosData.Status == GPSPOSITION_STATUS_FIX3D) {
520  msg_length += frsky_pack_gps(
521  gpsPosData.Heading,
522  gpsPosData.Latitude,
523  gpsPosData.Longitude,
524  gpsPosData.Altitude,
525  gpsPosData.Groundspeed,
526  shub_global->serial_buf + msg_length);
527  }
528 
529  msg_length += frsky_pack_stop(shub_global->serial_buf + msg_length);
530 
531  PIOS_COM_SendBuffer(shub_global->frsky_port,
532  shub_global->serial_buf, msg_length);
533  }
534  }
535 }
536 
537 static bool frame_trigger(uint8_t frame_num)
538 {
539  uint8_t rate = frsky_rates[frame_num];
540 
541  if (rate == 0) {
542  return false;
543  }
544 
545  if (shub_global->frame_ticks[frame_num] == 0) {
546  // we're triggering now, setup the next trigger point
547  if (rate > TASK_RATE_HZ) {
548  rate = TASK_RATE_HZ;
549  }
550  shub_global->frame_ticks[frame_num] = (TASK_RATE_HZ / rate);
551  return true;
552  }
553 
554  // count down at 50Hz
555  shub_global->frame_ticks[frame_num]--;
556  return false;
557 }
558 
563 static uint16_t frsky_pack_altitude(float altitude, uint8_t *serial_buf)
564 {
565  uint8_t index = 0;
566 
567  float altitudeInteger = 0.0f;
568 
569  uint16_t decimalValue = lroundf(modff(altitude, &altitudeInteger) * 100);
570  int16_t integerValue = lroundf(altitude);
571 
572  frsky_serialize_value(FRSKY_ALTITUDE_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
573  frsky_serialize_value(FRSKY_ALTITUDE_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
574 
575  return index;
576 }
577 
583  float temperature_01,
584  uint8_t *serial_buf)
585 {
586  uint8_t index = 0;
587 
588  int16_t temperature = lroundf(temperature_01);
589  frsky_serialize_value(FRSKY_TEMPERATURE_1, (uint8_t*)&temperature, serial_buf, &index);
590 
591  return index;
592 }
593 
599  float temperature_02,
600  uint8_t *serial_buf)
601 {
602  uint8_t index = 0;
603 
604  int16_t temperature = lroundf(temperature_02);
605  frsky_serialize_value(FRSKY_TEMPERATURE_2, (uint8_t*)&temperature, serial_buf, &index);
606 
607  return index;
608 }
609 
614 static uint16_t frsky_pack_accel(
615  float accels_x,
616  float accels_y,
617  float accels_z,
618  uint8_t *serial_buf)
619 {
620  uint8_t index = 0;
621 
622  int16_t accel = frsky_acceleration_unit(accels_x);
623  frsky_serialize_value(FRSKY_ACCELERATION_X, (uint8_t*)&accel, serial_buf, &index);
624 
625  accel = frsky_acceleration_unit(accels_y);
626  frsky_serialize_value(FRSKY_ACCELERATION_Y, (uint8_t*)&accel, serial_buf, &index);
627 
628  accel = frsky_acceleration_unit(accels_z);
629  frsky_serialize_value(FRSKY_ACCELERATION_Z, (uint8_t*)&accel, serial_buf, &index);
630 
631  return index;
632 }
633 
634 static uint16_t frsky_pack_cellvoltage(
635  uint8_t cell,
636  float cell_voltage,
637  uint8_t *serial_buf)
638 {
639  // its not possible to address more than 15 cells
640  if (cell > 15)
641  return 0;
642 
643  uint8_t index = 0;
644  uint16_t v = lroundf((cell_voltage / 4.2f) * 2100);
645  if (v > 2100)
646  v = 2100;
647 
648  uint16_t voltage = ((v & 0x00ff) << 8) | (cell << 4) | ((v & 0x0f00) >> 8);
649  frsky_serialize_value(FRSKY_VOLTAGE, (uint8_t*)&voltage, serial_buf, &index);
650 
651  return index;
652 }
657 static uint16_t frsky_pack_fas(
658  float voltage,
659  float current,
660  uint8_t *serial_buf)
661 {
662  uint8_t index = 0;
663 
664  voltage = (voltage * 110.0f) / 21.0f;
665 
666  uint16_t integerValue = lroundf(voltage) / 100;
667  uint16_t decimalValue = lroundf(voltage - integerValue);
668 
669  frsky_serialize_value(FRSKY_VOLTAGE_AMPERE_SENSOR_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
670  frsky_serialize_value(FRSKY_VOLTAGE_AMPERE_SENSOR_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
671 
672  integerValue = lroundf(current * 10);
673  frsky_serialize_value(FRSKY_CURRENT, (uint8_t*)&integerValue, serial_buf, &index);
674 
675  return index;
676 }
677 
682 static uint16_t frsky_pack_rpm(uint16_t rpm, uint8_t *serial_buf)
683 {
684  uint8_t index = 0;
685 
686  frsky_serialize_value(FRSKY_RPM, (uint8_t*)&rpm, serial_buf, &index);
687 
688  return index;
689 }
690 
695 static uint16_t frsky_pack_fuel(
696  float fuel_level,
697  uint8_t *serial_buf)
698 {
699  uint8_t index = 0;
700 
701  uint16_t level = lroundf(abs(fuel_level * 100));
702 
703  //Use fixed levels here because documentation says so.
704  if (level > 94)
705  level = 100;
706  else if (level > 69)
707  level = 75;
708  else if (level > 44)
709  level = 50;
710  else if (level > 19)
711  level = 25;
712  else
713  level = 0;
714 
715  frsky_serialize_value(FRSKY_FUEL_LEVEL, (uint8_t*)&level, serial_buf, &index);
716 
717  return index;
718 }
719 
724 static uint16_t frsky_pack_gps(
725  float course,
726  int32_t latitude,
727  int32_t longitude,
728  float altitude,
729  float speed,
730  uint8_t *serial_buf)
731 {
732  uint8_t index = 0;
733 
734  {
735  float courseInteger = 0.0f;
736  uint16_t decimalValue = lroundf(modff(course, &courseInteger) * 100);
737  uint16_t integerValue = lroundf(courseInteger);
738 
739  frsky_serialize_value(FRSKY_GPS_COURSE_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
740  frsky_serialize_value(FRSKY_GPS_COURSE_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
741  }
742 
743  // latitude
744  {
745  uint16_t integerValue = (abs(latitude) / 100000);
746  uint16_t decimalValue = (abs(latitude) / 10) % 10000;
747 
748  frsky_serialize_value(FRSKY_GPS_LATITUDE_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
749  frsky_serialize_value(FRSKY_GPS_LATITUDE_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
750 
751  uint16_t hemisphere = 'N';
752  if (latitude < 0) {
753  hemisphere = 'S';
754  }
755  frsky_serialize_value(FRSKY_GPS_N_S, (uint8_t*)&hemisphere, serial_buf, &index);
756  }
757 
758  // longitude
759  {
760  uint16_t integerValue = (abs(longitude) / 100000);
761  uint16_t decimalValue = (abs(longitude) / 10) % 10000;
762 
763  uint16_t hemisphere = 'E';
764  if (longitude < 0) {
765  hemisphere = 'W';
766  }
767 
768  frsky_serialize_value(FRSKY_GPS_LONGITUDE_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
769  frsky_serialize_value(FRSKY_GPS_LONGITUDE_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
770 
771  frsky_serialize_value(FRSKY_GPS_E_W, (uint8_t*)&hemisphere, serial_buf, &index);
772  }
773 
774  // speed
775  {
776  float knots = speed / KNOTS2M_PER_SECOND;
777 
778  float knotsInteger = 0.0f;
779  uint16_t decimalValue = lroundf(modff(knots, &knotsInteger) * 100);
780  int16_t integerValue = lroundf(knotsInteger);
781 
782  frsky_serialize_value(FRSKY_GPS_SPEED_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
783  frsky_serialize_value(FRSKY_GPS_SPEED_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
784  }
785 
786  // altitude
787  {
788  float altitudeInteger = 0.0;
789  uint16_t decimalValue = lroundf(modff(altitude, &altitudeInteger) * 100);
790  int16_t integerValue = lroundf(altitudeInteger);
791 
792  frsky_serialize_value(FRSKY_GPS_ALTITUDE_INTEGER, (uint8_t*)&integerValue, serial_buf, &index);
793  frsky_serialize_value(FRSKY_GPS_ALTITUDE_DECIMAL, (uint8_t*)&decimalValue, serial_buf, &index);
794  }
795 
796  return index;
797 }
798 
803 static uint16_t frsky_pack_stop(uint8_t *serial_buf)
804 {
805  serial_buf[0] = FRSKY_FRAME_STOP;
806 
807  return 1;
808 }
809 
814 static int16_t frsky_acceleration_unit(float accel)
815 {
816  accel = accel / GRAVITY; //convert to gravity
817  accel *= 1000;
818  return lroundf(accel);
819 }
820 
824 static void frsky_serialize_value(uint8_t valueid, uint8_t *value, uint8_t *serial_buf, uint8_t *index)
825 {
826  serial_buf[(*index)++] = FRSKY_FRAME_DATA_HEADER;
827  serial_buf[(*index)++] = valueid;
828 
829  frsky_write_userdata_byte(value[0], serial_buf, index);
830  frsky_write_userdata_byte(value[1], serial_buf, index);
831 }
832 
836 static void frsky_write_userdata_byte(uint8_t byte, uint8_t *serial_buf, uint8_t *index)
837 {
838  //** byte stuffing
839  if ((byte == 0x5E) || (byte == 0x5D)) {
840  serial_buf[(*index)++] = 0x5D;
841  serial_buf[(*index)++] = ~(byte ^ 0x60);
842  }
843  else {
844  serial_buf[(*index)++] = byte;
845  }
846 }
847 
uint16_t speed
Definition: msp_messages.h:101
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
static uint16_t frsky_pack_temperature_01(float temperature_01, uint8_t *serial_buf)
Main PiOS header to include all the compiled in PiOS options.
static uint16_t frsky_pack_fuel(float fuel_level, uint8_t *serial_buf)
#define PIOS_COM_FRSKY_SENSOR_HUB
Definition: pios_board.h:119
bool PIOS_Modules_IsEnabled(enum pios_modules module)
Definition: pios_modules.c:41
static bool frame_trigger(uint8_t frame_num)
#define STACK_SIZE_BYTES
Definition: actuator.c:62
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
static uint16_t frsky_pack_stop(uint8_t *serial_buf)
#define TASK_PRIORITY
Definition: actuator.c:65
static uint16_t frsky_pack_gps(float course, int32_t latitude, int32_t longitude, float altitude, float speed, uint8_t *serial_buf)
static uint16_t frsky_pack_altitude(float altitude, uint8_t *serial_buf)
int32_t longitude
int16_t status
Definition: main.c:61
AttitudeActualPitchGet & accY
#define MODULE_INITCALL(ifn, sfn)
Definition: pios_initcall.h:67
static int16_t frsky_acceleration_unit(float accel)
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
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
uint8_t i
Definition: msp_messages.h:97
float altitude
struct _msp_pid_item level
Definition: msp_messages.h:103
uint16_t value
Definition: storm32bgc.c:155
uint16_t current
case MODULESETTINGS_FRSKYACCELDATA_ATTITUDEANGLES
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
static uint16_t frsky_pack_accel(float accels_x, float accels_y, float accels_z, uint8_t *serial_buf)
static uint16_t frsky_pack_fas(float voltage, float current, uint8_t *serial_buf)
static void frsky_serialize_value(uint8_t valueid, uint8_t *value, uint8_t *serial_buf, uint8_t *index)
PIOS_COM_SendBuffer(shub_global->frsky_port, shub_global->serial_buf, msg_length)
uint8_t rate
Definition: msp_messages.h:99
tuple f
Definition: px_mkfw.py:81
static uint16_t frsky_pack_temperature_02(float temperature_02, uint8_t *serial_buf)
static void frsky_write_userdata_byte(uint8_t byte, uint8_t *serial_buf, uint8_t *index)
Includes PiOS and core architecture components.
static uint16_t frsky_pack_rpm(uint16_t rpm, uint8_t *serial_buf)
static uint16_t frsky_pack_cellvoltage(uint8_t cell, float cell_voltage, uint8_t *serial_buf)
uint16_t voltage
static uint32_t lastSysTime
int32_t latitude
AttitudeActualYawGet & accZ
int32_t PIOS_COM_ChangeBaud(uintptr_t com_id, uint32_t baud)