Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
max7456.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013-2020 Chris Efstathiou hendrixgr@gmail.com
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
28 #include "std.h"
29 //#include "stdio.h"
30 
31 #include "modules/core/commands.h"
32 
33 #include "mcu_periph/sys_time.h"
34 #include "mcu_periph/gpio.h"
35 #include "mcu_periph/spi.h"
36 
37 #include "generated/flight_plan.h"
38 #include "generated/airframe.h"
39 #include "autopilot.h"
41 #include "state.h"
42 
43 // for GetPosAlt, include correct header until we have unified API
44 #if defined(FIXEDWING_FIRMWARE)
45 //#include "modules/nav/nav.h"
46 #include "modules/nav/common_nav.h"
47 #elif defined(ROTORCRAFT_FIRMWARE)
49 #endif
50 #if DOWNLINK
52 #endif
53 
54 // Peripherials
57 
58 #define OSD_STRING_SIZE 31
59 #define osd_sprintf _osd_sprintf
60 
61 #if !defined(OSD_USE_FLOAT_LOW_PASS_FILTERING)
62 #define OSD_USE_FLOAT_LOW_PASS_FILTERING
63 #endif
64 
65 //LOW PASS filter strength, cannot be 0, MAX=16
66 #if !defined(AMPS_LOW_PASS_FILTER_STRENGTH) || AMPS_LOW_PASS_FILTER_STRENGTH == 0
67 #define AMPS_LOW_PASS_FILTER_STRENGTH 6
68 #endif
69 
70 #if !defined(SPEED_LOW_PASS_FILTER_STRENGTH) || SPEED_LOW_PASS_FILTER_STRENGTH == 0
71 #define SPEED_LOW_PASS_FILTER_STRENGTH 6
72 #endif
73 
74 #if !defined(BAT_CAPACITY)
75 #pragma message "BAT_CAPACITY not defined, 5000 mah will be used."
76 #define BAT_CAPACITY 5000.0
77 #endif
78 
79 #if defined(FIXEDWING_FIRMWARE)
80 
81 #if !defined(LOITER_BAT_CURRENT)
82 #pragma message "LOITER_BAT_CURRENT not defined, 10 Amps will be used for LOITER current draw."
83 #define LOITER_BAT_CURRENT 10.0
84 #endif
85 
86 #if !defined(STALL_AIRSPEED)
87 #pragma message "STALL_AIRSPEED not defined, 10 m/s will be used."
88 #define STALL_AIRSPEED 10.0
89 #endif
90 
91 #if !defined(MINIMUM_AIRSPEED)
92 #pragma message "MINIMUM_AIRSPEED not defined, 1.3 * STALL_SPEED will be used"
93 #define MINIMUM_AIRSPEED (1.3f * STALL_AIRSPEED)
94 #endif
95 
96 #endif
97 
98 #if !defined(IMU_MAG_X_SIGN)
99 #define IMU_MAG_X_SIGN 1
100 #endif
101 #if !defined(IMU_MAG_X_SIGN)
102 #define IMU_MAG_Y_SIGN 1
103 #endif
104 #if !defined(IMU_MAG_X_SIGN)
105 #define IMU_MAG_Z_SIGN 1
106 #endif
107 
108 
109 typedef struct {
110  float fx;
111  float fy;
112  float fz;
113 } VECTOR;
114 
115 typedef struct {
116  float fx1; float fx2; float fx3;
117  float fy1; float fy2; float fy3;
118  float fz1; float fz2; float fz3;
119 } MATRIX;
120 
121 #if defined(FIXEDWING_FIRMWARE)
122 static void mag_compass(void);
123 #endif
124 static void send_mag_heading(struct transport_tx *trans, struct link_device *dev);
125 static void vSubtractVectors(VECTOR *svA, VECTOR svB, VECTOR svC);
126 static void vMultiplyMatrixByVector(VECTOR *svA, MATRIX smB, VECTOR svC);
127 static float home_direction(void);
128 static char ascii_to_osd_c(char c);
129 static void calc_flight_time_left(void);
130 static void draw_osd(void);
131 static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column);
132 static bool _osd_sprintf(char *buffer, char *string, float value);
133 
135 
140 char osd_char = ' ';
144 
157 };
158 
162  L_JUST = 0x00,
163  R_JUST = 0x01,
164  C_JUST = 0x02,
165 
166 };
167 
173 
174 float mag_course_deg = 0;
175 float mag_heading_rad = 0;
176 float gps_course_deg = 0;
177 float home_dir_deg = 0;
178 
179 #if defined(FIXEDWING_FIRMWARE)
180 // Periodic function called with a frequency defined in the module .xml file
181 void mag_compass(void)
182 {
183 
184  struct FloatEulers *att = stateGetNedToBodyEulers_f();
185  float cos_roll; float sin_roll; float cos_pitch; float sin_pitch; float mag_x; float mag_y;
186  static float mag_declination = 0;
187  static bool declination_calculated = false;
188 
189  struct imu_mag_t *mag = imu_get_mag(ABI_BROADCAST, false);
190  if(mag == NULL)
191  return;
192 
193  cos_roll = cosf(att->phi);
194  sin_roll = sinf(att->phi);
195  cos_pitch = cosf(att->theta);
196  sin_pitch = sinf(att->theta);
197  // Pitch&Roll Compensation:
198  mag_x = mag->scaled.x * cos_pitch + mag->scaled.y * sin_roll * sin_pitch + mag->scaled.z * cos_roll * sin_pitch;
199  mag_y = mag->scaled.y * cos_roll - mag->scaled.z * sin_roll;
200 
201  // Magnetic Heading N = 0, E = 90, S = +-180, W = -90
202  mag_heading_rad = atan2(-mag_y, mag_x);
203 #if defined(AHRS_MAG_DECLINATION)
204  if (AHRS_MAG_DECLINATION != 0.0) {
205  //conversion from degrees to radians is done in the airframe.h file
206  mag_heading_rad = mag_heading_rad + AHRS_MAG_DECLINATION;
207  }
208 #endif
209  if (mag_heading_rad > M_PI) { // Angle normalization (-180 deg to 180 deg)
210  mag_heading_rad -= (2.0 * M_PI);
211  } else if (mag_heading_rad < -M_PI) { mag_heading_rad += (2.0 * M_PI); }
212 
213  if (declination_calculated == false) {
214 #if defined(NOMINAL_AIRSPEED)
215  if (gps.fix == GPS_FIX_3D && stateGetHorizontalSpeedNorm_f() > (float)NOMINAL_AIRSPEED) {
216 #else
217  if (gps.fix == GPS_FIX_3D && stateGetHorizontalSpeedNorm_f() > 10.0) {
218 #endif
219  mag_declination = stateGetHorizontalSpeedDir_f();
220  if (mag_declination > M_PI) { // Angle normalization (-180 deg to 180 deg)
221  mag_declination -= (2.0 * M_PI);
222  } else if (mag_declination < -M_PI) { mag_declination += (2.0 * M_PI); }
223  mag_declination -= mag_heading_rad;
224  declination_calculated = true;
225  if (fabs(mag_declination) > RadOfDeg(10.)) { mag_declination = 0; declination_calculated = false; }
226  }
227  }
228  mag_heading_rad = mag_heading_rad + mag_declination;
229  if (mag_heading_rad > M_PI) { // Angle normalization (-180 deg to 180 deg)
230  mag_heading_rad -= (2.0 * M_PI);
231  } else if (mag_heading_rad < -M_PI) { mag_heading_rad += (2.0 * M_PI); }
232  // Magnetic COMPASS Heading N = 0, E = 90, S = 180, W = 270
233  mag_course_deg = DegOfRad(mag_heading_rad);
234  if (mag_course_deg < 0) { mag_course_deg += 360; }
235 
236  return;
237 }
238 #endif
239 
240 
241 static void send_mag_heading(struct transport_tx *trans, struct link_device *dev)
242 {
244 #if DOWNLINK
245  pprz_msg_send_IMU_MAG(trans, dev, AC_ID, &abi_id, &mag_course_deg, &gps_course_deg, &home_dir_deg);
246 #endif
247 
248  return;
249 }
250 
251 //*******************************************************************
252 // function name: vSubtractVectors
253 // description: subtracts two vectors a = b - c
254 // parameters:
255 //*******************************************************************
256 static void vSubtractVectors(VECTOR *svA, VECTOR svB, VECTOR svC)
257 {
258  svA->fx = svB.fx - svC.fx;
259  svA->fy = svB.fy - svC.fy;
260  svA->fz = svB.fz - svC.fz;
261 }
262 
263 //*******************************************************************
264 // function name: vMultiplyMatrixByVector
265 // description: multiplies matrix by vector svA = smB * svC
266 // parameters:
267 //*******************************************************************
268 static void vMultiplyMatrixByVector(VECTOR *svA, MATRIX smB, VECTOR svC)
269 {
270  svA->fx = smB.fx1 * svC.fx + smB.fx2 * svC.fy + smB.fx3 * svC.fz;
271  svA->fy = smB.fy1 * svC.fx + smB.fy2 * svC.fy + smB.fy3 * svC.fz;
272  svA->fz = smB.fz1 * svC.fx + smB.fz2 * svC.fy + smB.fz3 * svC.fz;
273 }
274 
275 
276 static float home_direction(void)
277 {
278 
279  static VECTOR svPlanePosition, Home_Position, Home_PositionForPlane, Home_PositionForPlane2;
280  static MATRIX smRotation;
281  float home_dir = 0;
282 
283 
284  /*
285  By swapping coordinates (fx=fPlaneNorth, fy=fPlaneEast) we make the the circle angle go from 0 (0 is to the top of the circle)
286  to 360 degrees or from 0 radians to 2 PI radians in a clockwise rotation. This way the GPS reported angle can be directly
287  applied to the rotation matrices (in radians).
288  In standard mathematical notation 0 is to the right (East) of the circle, -90 is to the bottom, +-180 is to the left
289  and +90 is to the top (counterclockwise rotation).
290  When reading back the actual rotated coordinates fx has the y coordinate and fy has the x when
291  represented on a circle in standard mathematical notation.
292  */
293  if (gps.fix == GPS_FIX_3D && stateGetHorizontalSpeedNorm_f() > 5.0) { //Only when flying
294  svPlanePosition.fx = stateGetPositionEnu_f()->y;
295  svPlanePosition.fy = stateGetPositionEnu_f()->x;
296  svPlanePosition.fz = stateGetPositionUtm_f()->alt;
297 #if defined(FIXEDWING_FIRMWARE)
298  Home_Position.fx = WaypointY(WP_HOME);
299  Home_Position.fy = WaypointX(WP_HOME);
300  Home_Position.fz = GetAltRef();
301 #else
302  Home_Position.fx = waypoint_get_x(WP_HOME);
303  Home_Position.fy = waypoint_get_y(WP_HOME);
304  Home_Position.fz = 0;
305 #endif
306 
307  /* distance between plane and object */
308  vSubtractVectors(&Home_PositionForPlane, Home_Position, svPlanePosition);
309 
310  /* yaw */
311  smRotation.fx1 = cosf(stateGetHorizontalSpeedDir_f());
312  smRotation.fx2 = sinf(stateGetHorizontalSpeedDir_f());
313  smRotation.fx3 = 0.;
314  smRotation.fy1 = -smRotation.fx2;
315  smRotation.fy2 = smRotation.fx1;
316  smRotation.fy3 = 0.;
317  smRotation.fz1 = 0.;
318  smRotation.fz2 = 0.;
319  smRotation.fz3 = 1.;
320 
321  vMultiplyMatrixByVector(&Home_PositionForPlane2, smRotation, Home_PositionForPlane);
322 
323  /* DEFAULT ORIENTATION IS 0 = FRONT, 90 = RIGHT, 180 = BACK, -90 = LEFT
324  *
325  * WHEN home_dir = (float)(atan2(Home_PositionForPlane2.fy, (Home_PositionForPlane2.fx)));
326  *
327  * plane front
328  * 0Ëš
329  * ^
330  * I
331  * -45Ëš I 45Ëš
332  * \ I /
333  * \I/
334  * -90Ëš-------I------- 90Ëš
335  * /I\
336  * / I \
337  * -135Ëš I 135Ëš
338  * I
339  * 180
340  * plane back
341  *
342  *
343  * When the home_dir variable goes to 0 the aircraft is headed straight back home
344  */
345 
346  /* fixed to the plane*/
347  home_dir = atan2(Home_PositionForPlane2.fy, Home_PositionForPlane2.fx);
348  if (home_dir > M_PI) { // Angle normalization (-180 deg to 180 deg but still in radians)
349  home_dir -= (2.0 * M_PI);
350  } else if (home_dir < -M_PI) { home_dir += (2.0 * M_PI); }
351  home_dir_deg = DegOfRad(home_dir); // Now convert radians to degrees.
352 
353  } // END OF if (gps.fix == GPS_FIX_3D) statement.
354 
355  return (home_dir_deg);
356 }
357 
358 static char ascii_to_osd_c(char c)
359 {
360 
361 #if defined USE_MATEK_TYPE_OSD_CHIP && USE_MATEK_TYPE_OSD_CHIP == 1
362  PRINT_CONFIG_MSG("OSD USES THE CUSTOM MATEK TYPE OSD CHIP")
363 
364  return (c);
365 
366 #else
367  PRINT_CONFIG_MSG("OSD USES THE STANDARF MAX7456 OSD CHIP")
368 
369  if (c >= '0' && c <= '9') {
370  if (c == '0') { c -= 38; } else { c -= 48; }
371  } else if (c >= 'A' && c <= 'Z') {
372  c -= 54;
373  } else if (c >= 'a' && c <= 'z') {
374  c -= 60;
375 
376  } else {
377  switch (c) {
378  case ('('): c = 0x3f; break;
379  case (')'): c = 0x40; break;
380  case ('.'): c = 0x41; break;
381  case ('?'): c = 0x42; break;
382  case (';'): c = 0x43; break;
383  case (':'): c = 0x44; break;
384  case (','): c = 0x45; break;
385  //case('''): c = 0x46; break;
386  case ('/'): c = 0x47; break;
387  case ('"'): c = 0x48; break;
388  case ('-'): c = 0x49; break;
389  case ('<'): c = 0x4A; break;
390  case ('>'): c = 0x4B; break;
391  case ('@'): c = 0x4C; break;
392  case (' '): c = 0x00; break;
393  case ('\0'): c = 0xFF; break;
394  default : break;
395  }
396  }
397 
398  return (c);
399 
400 #endif
401 }
402 
403 static void calc_flight_time_left(void)
404 {
405  float current_amps = 0;
406  float horizontal_speed = 0;
407  float bat_capacity_left = 0;
408  static float bat_capacity_used = 0;
409 
410 
411  current_amps = electrical.current;
412  bat_capacity_used += (current_amps * 1000.) / (3600. * (float)MAX7456_PERIODIC_FREQ);
413  bat_capacity_left = (float)BAT_CAPACITY - bat_capacity_used;
414  if (bat_capacity_left < 0) { bat_capacity_left = 0; }
415  horizontal_speed = stateGetHorizontalSpeedNorm_f();
416 
417 #if defined(FIXEDWING_FIRMWARE)
418  if (stateGetHorizontalSpeedNorm_f() < 5.0 || autopilot.launch == false) {
419  current_amps = LOITER_BAT_CURRENT;
420  horizontal_speed = MINIMUM_AIRSPEED;
421  }
422 #else // #if !FW
423  current_amps = 1.0; // FIXME, Find how to tell if the rotorcraft is on the ground or it is flying.
424  horizontal_speed = 10.0;
425 #endif
426 
427 #if defined(OSD_USE_FLOAT_LOW_PASS_FILTERING)
428 
429  static double current_amps_sum = 0;
430  static double horizontal_speed_sum = 0;
431  static float current_amps_filtered = 0;
432  static float horizontal_speed_filtered = 0;
433 
434  current_amps_sum = (current_amps_sum - current_amps_filtered) + current_amps;
435  current_amps_filtered = current_amps_sum / (1 << AMPS_LOW_PASS_FILTER_STRENGTH);
436  current_amps = current_amps_filtered;
437 
438  horizontal_speed_sum = (horizontal_speed_sum - horizontal_speed_filtered) + horizontal_speed;
439  horizontal_speed_filtered = horizontal_speed_sum / (1 << SPEED_LOW_PASS_FILTER_STRENGTH);
440  horizontal_speed = horizontal_speed_filtered;
441 
442 #else
443 
444  uint32_t current_amps_int = 0;
445  uint32_t horizontal_speed_int = 0;
446  static uint64_t current_amps_sum = 0;
447  static uint64_t horizontal_speed_sum = 0;
448  static uint32_t current_amps_filtered = 0;
449  static uint32_t horizontal_speed_filtered = 0;
450 
451  // LOW PASS FILTERS for making the OSD 'max_flyable_distance_left' var change more gently.
452  current_amps_int = (uint32_t)(current_amps * 1000.0);
453  horizontal_speed_int = (uint32_t)(horizontal_speed * 1000.0);
454 
455  current_amps_sum = (current_amps_sum - current_amps_filtered) + current_amps_int;
456  current_amps_filtered = (current_amps_sum + (1 << (AMPS_LOW_PASS_FILTER_STRENGTH - 1))) >>
458 
459  horizontal_speed_sum = (horizontal_speed_sum - horizontal_speed_filtered) + horizontal_speed_int;
460  horizontal_speed_filtered = (horizontal_speed_sum + (1 << (SPEED_LOW_PASS_FILTER_STRENGTH - 1))) >>
462 
463  current_amps = (float)(current_amps_filtered) / 1000.;
464  horizontal_speed = (float)(horizontal_speed_filtered) / 1000.;
465 
466 #endif
467 
468  max_flyable_distance_left = ((bat_capacity_left / (current_amps * 1000)) * 3600) * horizontal_speed;
469 
470  return;
471 }
472 
473 
474 static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column)
475 {
476 
477  int8_t x = 0, idx = 0, post_offset = 0, aft_offset = 0, string_len = 0;
478  char osd_buf[OSD_STRING_SIZE];
479 
480  if (row > 15) { column = 15; }
481  if (column > 29) { column = 29; }
482 
483 // translate the string and put it to the "osd_string" '\0' = 0xff
484  x = 0;
485  while (*(string + x) != '\0') { osd_string[x] = ascii_to_osd_c(*(string + x)); x++; }
486  osd_string[x] = 0xff;
487  string_len = x;
488  idx = x;
489 
490  if (attributes & C_JUST) {
491  if (char_nb % 2 == 0) { char_nb++; }
492  post_offset = (char_nb - string_len) / 2;
493  aft_offset = char_nb - string_len;
494  if (((int8_t)column - (char_nb / 2)) >= 0) { column -= (char_nb / 2); }
495  for (x = 0; x < 30; x++) { osd_buf[x] = 0; } // FILL WITH SPACES
496  // COPY THE ORIGINAL STRING TO ITS NEW POSITION
497  for (x = 0; x < string_len; x++) { osd_buf[post_offset + x] = osd_string[x]; }
498  osd_buf[string_len + aft_offset] = 0xFF; // TERMINATE THE MODIFIED STRING
499  // COPY THE MODIFIED STRING TO MAIN OSD STRING
500  x = 0;
501  do { osd_string[x] = osd_buf[x]; } while (osd_buf[x++] != 0xFF);
502  } else if (attributes & R_JUST) {
503  //if(x){ x -= 1; }
504  //if (char_nb < string_len){ char_nb = string_len; }
505  if (((int8_t)column - char_nb) >= 0) { column -= char_nb; }
506  if (((int8_t)char_nb - string_len) >= 0) { post_offset = char_nb - string_len; } else {post_offset = 0; }
507  //ADD LEADING SPACES
508  //First shift right the string and then add spaces at the beggining
509  while (idx >= 0) { osd_string[idx + post_offset] = osd_string[idx]; idx--; }
510  idx = 0;
511  while (idx < post_offset) { osd_string[idx] = 0; idx++; }
512  //osd_string[idx] = 0xff;
513 
514  } else {
515  //Adjust for the reserved character number.
516  for (x = 0; x < (int8_t)(sizeof(osd_string)); x++) { if (osd_string[x] == 0xFF) { break; } }
517  for (; x < char_nb; x++) { osd_string[x] = 0; }
518  osd_string[x] = 0xff;
519  }
520 
521  osd_char_address = ((uint16_t)row * 30) + column;
522  osd_attr = (attributes & (BLINK | INVERT));
523 //TRIGGER THE SPI TRANSFERS. The rest of the spi transfers occur in the "max7456_event" function.
524  if (max7456_osd_status == OSD_IDLE) {
527  max7456_trans.output_buf[1] = (uint8_t)((osd_char_address >> 8) & 0x0001);
529  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
530 
531  }
532 
533  return;
534 }
535 
536 
537 static bool _osd_sprintf(char *buffer, char *string, float value)
538 {
539  uint8_t param_start = 0;
540  uint8_t param_end = 0;
541  uint8_t frac_nb = 0;
542  uint8_t digit = 0;
543  uint8_t x = 0, y = 0, z = 0;
544 
545  uint16_t i_dec = 0;
546  uint16_t i_frac = 0;
547 
548  char to_asc[10] = {48, 48, 48, 48, 48, 48, 48, 48, 48, 48};
549  char string_buf[OSD_STRING_SIZE];
550 
551 // Clear the osd string.
552  for (x = 0; x < sizeof(osd_string); x++) { osd_string[x] = 0; }
553  for (x = 0; x < sizeof(string_buf); x++) { string_buf[x] = 0; }
554 
555 //copy the string passed as parameter to a buffer
556  for (x = 0; x < sizeof(string_buf); x++) { string_buf[x] = *(string + x); if (string_buf[x] == '\0') { break; } }
557  do {
558  x = 0;
559  param_start = 0;
560  param_end = 0;
561  //Now check for any special character
562  while (string_buf[x] != '\0') {
563  // EXAMPLE: in "%160c"x is '%' x+4 = 'c' and x+1='1', x+2='6' and x+3='0'
564  if (string_buf[x] == '%') { if (string_buf[x + 4] == 'c') { (param_start = x + 1); param_end = x + 3; break; } }
565  x++;
566  }
567  if (param_end - param_start) {
568  //load the special character value where the % character was
569  string_buf[x] = ((string_buf[param_start] - 48) * 100) + ((string_buf[param_start + 1] - 48) * 10) +
570  (string_buf[param_start + 2] - 48);
571  x++; // increment x to the next character which should be the first special character's digit
572  //Move the rest of the buffer forward so only the special character remains,
573  // for example in %170c '%' now has the special character's code and x now points to '1'
574  // which will be overwritten with the rest of the string after the 'c'
575  for (y = (x + 4); y <= sizeof(string_buf); y++) { string_buf[x++] = string_buf[y]; }
576  }
577  } while ((param_end - param_start > 0));
578 
579 // RESET THE USED VARIABLES JUST TO BE SAFE.
580  x = 0;
581  y = 0;
582  param_start = 0;
583  param_end = 0;
584 // Search for the prameter start and stop positions.
585  while (string_buf[x] != '\0') {
586  if (string_buf[x] == '%') {
587  param_start = x;
588 
589  } else if (string_buf[x] == 'f') { param_end = x; break; }
590  x++;
591  }
592  if (param_end - param_start) {
593  // find and bound the precision specified.
594  frac_nb = string_buf[param_end - 1] - 48; // Convert to number, ASCII 48 = '0'
595  if (frac_nb > 3) { frac_nb = 3; } // Bound value.
596 
597  y = (sizeof(to_asc) - 1); // Point y to the end of the array.
598  i_dec = abs((int16_t)value);
599  // Fist we will deal with the fractional part if specified.
600  if (frac_nb > 0 && frac_nb <= 3) {
601  i_frac = abs((int16_t)((value - (int16_t)value) * 1000)); // Max precision is 3 digits.
602  x = 100;
603  z = frac_nb;
604  do { // Example if frac_nb=2 then 952 will show as .95
605  z--;
606  digit = (i_frac / x);
607  to_asc[y + z] = digit + 48; // Convert to ASCII
608  i_frac -= digit * x; // Calculate the remainder.
609  x /= 10; // 952-(9*100) = 52, 52-(10*5)=2 etc.
610 
611  } while (z > 0);
612 
613  y -= frac_nb; // set y to point where the dot must be placed.
614  to_asc[y] = '.';
615  y--; // Set y to point where the rest of the numbers must be written.
616 
617  } // if (frac_nb > 0 && frac_nb <= 3){
618 
619  // Now it is time for the integer part. "y" already points to the position just before the dot.
620  do {
621  to_asc[y] = (i_dec % 10) + 48; //Write at least one digit even if value is zero.
622  i_dec /= 10;
623  if (i_dec <= 0) { // This way the leading zero is ommited.
624  if (value < 0) { y--; to_asc[y] = '-'; } // Place the minus sign if needed.
625  break;
626 
627  } else { y--; }
628 
629  } while (1);
630 
631  // Fill the buffer with the characters in the beggining of the string if any.
632  for (x = 0; x < param_start; x++) { *(buffer + x) = string_buf[x]; }
633 
634  // x is now pointing to the next character in osd_string.
635  // y is already pointing to the first digit or negative sign in "to_asc" array.
636  while (y < sizeof(to_asc)) { *(buffer + x) = to_asc[y]; x++; y++; }
637  // x is now pointing to the next character in osd_string.
638  // "param_end" is pointing to the last format character in the string.
639  do {
640  param_end++;
641  *(buffer + x++) = string_buf[param_end];
642 
643  } while (string_buf[param_end] != '\0'); //Write the rest of the string including the terminating char.
644 
645  // End of if (param_end - param_start)
646  } else {
647  for (x = 0; x < sizeof(string_buf); x++) {
648  *(buffer + x) = string_buf[x]; //Write the rest of the string including the terminating char.
649  if (*(buffer + x) == '\0') { break; }
650  }
651  }
652 
653  return (0);
654 }
655 
656 void draw_osd(void)
657 {
658  float temp = 0;
659  float altitude = 0;
660  float distance_to_home = 0;
661  static float home_direction_degrees = 0;
662 #if defined(BARO_ALTITUDE_VAR)
663  static float baro_alt_correction = 0;
664 #endif
665 
666  struct FloatEulers *att = stateGetNedToBodyEulers_f();
667  struct EnuCoor_f *pos = stateGetPositionEnu_f();
668 #if defined(FIXEDWING_FIRMWARE)
669  float ph_x = waypoints[WP_HOME].x - pos->x;
670  float ph_y = waypoints[WP_HOME].y - pos->y;
671  float stall_speed = STALL_AIRSPEED;
672 #else // FOR ROTORCRAFTS
673  float ph_x = waypoint_get_x(WP_HOME) - pos->x;
674  float ph_y = waypoint_get_y(WP_HOME) - pos->y;
675 #endif //
676 
677  distance_to_home = (float)(sqrt(ph_x * ph_x + ph_y * ph_y));
679 #if defined(FIXEDWING_FIRMWARE)
680  mag_compass();
681 #endif
682 
683  //THE SWITCH STATEMENT ENSURES THAT ONLY ONE SPI TRANSACTION WILL OCUUR IN EVERY PERIODIC FUNCTION CALL
684  switch (step) {
685 
686  case (0):
687  if (gps.fix == GPS_FIX_3D && stateGetHorizontalSpeedNorm_f() > 10.0) { //Only when flying
688  gps_course_deg = (float)gps.course;
689  gps_course_deg = DegOfRad(gps_course_deg / 1e7);
690  } else {
691 #if defined(FIXEDWING_FIRMWARE)
693 #else
695 #endif
696  }
698  osd_put_s(osd_string, C_JUST, 3, 1, 15);
699  step = 10;
700  break;
701 
702  case (10):
703  //Only when flying because i need this indication to remain stable if the GPS is lost.
704  // This way i can still have the synchronized magnetic compass heading and the last bearing home.
705  if (gps.fix == GPS_FIX_3D && gps.pdop < 1000 && stateGetHorizontalSpeedNorm_f() > 5.0) { //Only when flying
706  home_direction_degrees = gps_course_deg + home_direction(); //home_direction returns degrees -180 to +180
707  if (home_direction_degrees < 0) { home_direction_degrees += 360; } // translate the -180, +180 to 0-360.
708  if (home_direction_degrees >= 360) { home_direction_degrees -= 360; }
709  }
710 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
711  // All special character codes must be in 3 digit format!
712  osd_sprintf(osd_string, "%191c%.0f", home_direction_degrees); // 0 when heading straight back home.
713  osd_put_s(osd_string, C_JUST, 5, 2, 15); // "false = L_JUST
714 #else
715  osd_sprintf(osd_string, "H%.0f", home_direction_degrees);
716  osd_put_s(osd_string, C_JUST, 5, 2, 15); // "false = L_JUST
717 
718 #endif
719  step = 20;
720  break;
721 
722  case (20):
723  temp = ((float)electrical.vsupply);
724  osd_sprintf(osd_string, "%.1fV", temp);
725  if (temp > LOW_BAT_LEVEL) {
726  osd_put_s(osd_string, L_JUST, 5, 1, 1);
727 
728  } else { osd_put_s(osd_string, (L_JUST | BLINK | INVERT), 5, 1, 1); }
729  step = 30;
730  break;
731 
732  case (30):
733  if (gps.fix == GPS_FIX_3D) {
734 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
735  //Since we only send one special character the float variable is replaced by a zero.
736  osd_sprintf(osd_string, "%030c%031c", 0);
737  osd_put_s(osd_string, false, 2, 2, 1);
738 #else
739  osd_put_s("**", false, 2, 2, 1);
740 #endif
741  } else {
742 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
743  //Since we only send one special character the float variable is replaced by a zero.
744  osd_sprintf(osd_string, "%030c%031c", 0); // ALL special osd chars must have 3 digits.
745  osd_put_s(osd_string, (L_JUST | BLINK), 2, 2, 1);
746 #else
747  osd_put_s("**", (L_JUST | BLINK), 2, 2, 1);
748 #endif
749  }
750  step = 40;
751  break;
752 
753  case (40):
754 #if defined(FIXEDWING_FIRMWARE)
755  if (autopilot.mode == AP_MODE_AUTO2) {
756  osd_put_s("A2", L_JUST, 2, 2, 3);
757  } else if (autopilot.mode == AP_MODE_AUTO1) {
758  osd_put_s("A1", L_JUST, 2, 2, 3);
759  } else {
760  osd_put_s("MAN", L_JUST, 3, 2, 3);
761  }
762 #endif
763  step = 50;
764  break;
765 
766  case (50):
767 #if defined(FIXEDWING_FIRMWARE)
768  osd_sprintf(osd_string, "THR%.0f", (((float)command_get(COMMAND_THROTTLE) / (float)MAX_PPRZ) * 100.));
769 #else
770  osd_sprintf(osd_string, "THR%.0fTHR", (((float)stabilization_cmd[COMMAND_THRUST] / (float)MAX_PPRZ) * 100.));
771 #endif
772  osd_put_s(osd_string, L_JUST, 6, 3, 1);
773  step = 60;
774  break;
775 
776  case (60):
777 #if defined(FIXEDWING_FIRMWARE)
778 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
779  if ((fabs(stateGetHorizontalSpeedNorm_f() * cos(att->phi))) < stall_speed) {
780  osd_sprintf(osd_string, "STALL!", 0);
781  osd_put_s(osd_string, (R_JUST | BLINK), 6, 1, 30);
782  } else {
783  osd_sprintf(osd_string, "%.0f%161c", (stateGetHorizontalSpeedNorm_f() * 3.6));
784  osd_put_s(osd_string, R_JUST, 6, 1, 30);
785  }
786 #else
787  if ((fabs(stateGetHorizontalSpeedNorm_f() * cos(att->phi))) < stall_speed) {
788  osd_sprintf(osd_string, "STALL!", 0);
789  osd_put_s(osd_string, (R_JUST | BLINK), 6, 1, 30);
790  } else {
792  osd_put_s(osd_string, R_JUST, 6, 1, 30);
793  }
794 #endif
795 
796 #else // #if !FW
797 
798 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
799  osd_sprintf(osd_string, "%.0f%161c", (stateGetHorizontalSpeedNorm_f() * 3.6));
800 #else
802 #endif
803  osd_put_s(osd_string, R_JUST, 6, 1, 30);
804 
805 #endif
806  step = 70;
807  break;
808 
809  case (70):
810 #if defined(BARO_ALTITUDE_VAR)
811  if (gps.fix == GPS_FIX_3D && gps.pdop < 1000) {
812  RunOnceEvery((MAX7456_PERIODIC_FREQ * 300), { baro_alt_correction = GetPosAlt() - BARO_ALTITUDE_VAR;});
813  altitude = GetPosAlt();
814  } else {
815  altitude = BARO_ALTITUDE_VAR + baro_alt_correction;
816  }
817 #else
818  altitude = GetPosAlt();
819 #endif
820 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
821  osd_sprintf(osd_string, "%.0f%177c", altitude);
822 #else
823  osd_sprintf(osd_string, "%.0fM", altitude);
824 #endif
825  osd_put_s(osd_string, R_JUST, 6, 2, 30); // "false = L_JUST
826  step = 80;
827  break;
828 
829  case (80):
830 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
831  osd_sprintf(osd_string, "%.1f%159c", stateGetSpeedEnu_f()->z);
832 #else
834 #endif
835  if (stateGetSpeedEnu_f()->z > 3.0) {
836  osd_put_s(osd_string, (R_JUST | BLINK), 6, 3, 30);
837  } else {
838  osd_put_s(osd_string, R_JUST, 6, 3, 30);
839  }
840  step = 90;
841  break;
842 
843  case (90):
844 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
845  // ANY SPECIAL CHARACTER CODE MUST BE A 3 DIGIT NUMBER WITH THE LEADING ZEROS!!!!
846  // THE SPECIAL CHARACTER CAN BE PLACED BEFORE OR AFTER THE FLOAT OR ANY OTHER CHARACTER
847  osd_sprintf(osd_string, "%160c%.1fK%012c", (distance_to_home / 1000));
848  osd_put_s(osd_string, L_JUST, 7, 15, 1);
849 #else
850  osd_sprintf(osd_string, "%.1fKM", (distance_to_home / 1000));
851  osd_put_s(osd_string, L_JUST, 7, 15, 1);
852 #endif
853  step = 100;
854  break;
855 
856  case (100):
857 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
858  osd_sprintf(osd_string, "%147c%.1fK%012c", (max_flyable_distance_left / 1000));
859 #else
860  osd_sprintf(osd_string, "%.1fKM", (max_flyable_distance_left / 1000));
861 #endif
862  if ((max_flyable_distance_left + 1000.0) < distance_to_home) {
863  osd_put_s(osd_string, (R_JUST | BLINK), 7, 15, 30);
864  } else {
865  osd_put_s(osd_string, (R_JUST), 7, 15, 30);
866  }
867  step = 110;
868  break;
869 
870  // A Text PFD as graphics are not the strong point of the MAX7456
871  // In order to level the aircraft while fpving
872  // just move the stick to the opposite direction from the angles shown on the osd
873  // and that's why positive pitch (UP) is shown below the OSD center
874  case (110):
875  if (DegOfRad(att->theta) > 3) {
876  osd_sprintf(osd_string, "%.0f", DegOfRad(att->theta));
877  osd_put_s(osd_string, C_JUST, 5, 6, 15);
878 
879  } else { osd_put_s(" ", C_JUST, 5, 6, 15); }
880  step = 112;
881  break;
882 
883  case (112):
884  if (DegOfRad(att->theta) < -3) {
885  osd_sprintf(osd_string, "%.0f", DegOfRad(att->theta));
886  osd_put_s(osd_string, C_JUST, 5, 10, 15);
887 
888  } else { osd_put_s(" ", C_JUST, 5, 10, 15); }
889  step = 114;
890  break;
891 
892  case (114):
893  if (DegOfRad(att->phi) > 3) {
894  osd_sprintf(osd_string, "%.0f>", DegOfRad(att->phi));
895  osd_put_s(osd_string, false, 5, 8, 18);
896 
897  } else { osd_put_s(" ", false, 5, 8, 18); }
898  step = 116;
899  break;
900 
901  case (116):
902  if (DegOfRad(att->phi) < -3) {
903  osd_sprintf(osd_string, "<%.0f", DegOfRad(fabs(att->phi)));
904  osd_put_s(osd_string, R_JUST, 5, 8, 13);
905 
906  } else { osd_put_s(" ", R_JUST, 5, 8, 13); }
907  step = 120;
908  break;
909 
910  case (120):
911 #if defined(USE_MATEK_TYPE_OSD_CHIP) && USE_MATEK_TYPE_OSD_CHIP == 1
912  osd_sprintf(osd_string, "%126c", 0);
913  osd_put_s(osd_string, false, 1, 8, 15); // false = L_JUST
914 #else
915  osd_put_s("+", false, 1, 8, 15); // false = L_JUST
916 #endif
917  step = 0;
918  break;
919 
920  default: step = 0; break;
921  } // End of switch statement.
922 
923  return;
924 }
925 
926 void max7456_init(void)
927 {
928 
929  max7456_trans.slave_idx = MAX7456_SLAVE_IDX;
940  max7456_trans.before_cb = NULL;
941  max7456_trans.after_cb = NULL;
942 
943  osd_enable = 1;
946 
947 #if DOWNLINK
949 #endif
950  home_direction();
951 
952  return;
953 }
954 
956 {
957 
958  //This code is executed always and checks if the "osd_enable" var has been changed by telemetry.
959  //If yes then it commands a reset but this time turns on or off the osd overlay, not the video.
960  if (max7456_osd_status == OSD_IDLE) {
961  if (osd_enable > 1) {
962  osd_enable = 1;
963  }
964  if ((osd_enable << 3) != osd_enable_val) {
965  osd_enable_val = (osd_enable << 3);
967  }
968  }
969 
970  //INITIALIZATION OF THE OSD
972  step = 0;
975  //This operation needs at least 100us but when the periodic function will be invoked again
976  //sufficient time will have elapsed even with at a periodic frequency of 1000 Hz
978  //We give an extra delay step by going to the event function and back here for the Reset to complete.
980  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
981  } else if (max7456_osd_status == OSD_INIT2) {
986  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
987  } else if (max7456_osd_status == OSD_IDLE && osd_enable > 0) {
988  draw_osd();
989  } // End of if (max7456_osd_status == OSD_UNINIT)
990 
991 
992 
993  return;
994 }
995 
996 void max7456_event(void)
997 {
998 
999  static uint8_t x = 0;
1000 
1003 
1004  switch (max7456_osd_status) {
1005  case (OSD_INIT1):
1007  break;
1008  case (OSD_INIT3):
1012  //Max7456 requires that you read first and then change only bit4 of the OSDBL register.
1013  //Reading was started in the periodic function and now we rerwrite the OSDBL register.
1014  max7456_trans.output_buf[1] = max7456_trans.input_buf[1] & (~(1 << 4));
1016  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1017  break;
1018  case (OSD_INIT4):
1020 #if USE_PAL_FOR_OSD_VIDEO
1021 #pragma message "Camera and OSD must be both PAL or NTSC otherwise only the camera picture will be visible."
1023 #else
1025 #endif
1027  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1028  break;
1029  case (OSD_S_STEP1):
1034  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1035  break;
1036  case (OSD_S_STEP2):
1041  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1042  x = 0;
1043  break;
1044  case (OSD_S_STEP3):
1045  max7456_trans.output_length = 1; //1 byte tranfers, auto address incrementing.
1046  if (osd_string[x] != 0XFF) {
1048  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1049  } else {
1050  max7456_trans.output_buf[0] = 0xFF; //Exit the auto increment mode
1052  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1053  }
1054  break;
1055  case (OSD_FINISHED):
1060  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1061  break;
1062  case (OSD_READ_STATUS):
1069  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
1070  } else {
1071  osd_attr = 0;
1074  }
1075  break;
1076 
1077  default: break;
1078  }
1079  }
1080  return;
1081 }
#define ABI_BROADCAST
Broadcast address.
Definition: abi_common.h:58
static int32_t altitude
Definition: airspeed_uADC.c:59
struct pprz_autopilot autopilot
Global autopilot structure.
Definition: autopilot.c:49
Core autopilot interface common to all firmwares.
bool launch
request launch
Definition: autopilot.h:71
uint8_t mode
current autopilot mode
Definition: autopilot.h:63
Hardware independent code for commands handling.
struct point waypoints[NB_WAYPOINT]
size == nb_waypoint, waypoint 0 is a dummy waypoint
Definition: common_nav.c:39
#define WaypointX(_wp)
Definition: common_nav.h:45
float y
Definition: common_nav.h:41
float x
Definition: common_nav.h:40
#define WaypointY(_wp)
Definition: common_nav.h:46
struct Electrical electrical
Definition: electrical.c:92
Interface for electrical status: supply voltage, current, battery status, etc.
#define LOW_BAT_LEVEL
low battery level in Volts (for 3S LiPo)
Definition: electrical.h:36
float current
current in A
Definition: electrical.h:47
float vsupply
supply voltage in V
Definition: electrical.h:45
#define STALL_AIRSPEED
Definition: energy_ctrl.c:148
#define AP_MODE_AUTO2
#define AP_MODE_AUTO1
Some architecture independent helper functions for GPIOs.
struct GpsState gps
global GPS state
Definition: gps.c:69
int32_t course
GPS course over ground in rad*1e7, [0, 2*Pi]*1e7 (CW/north)
Definition: gps.h:97
uint16_t pdop
position dilution of precision scaled by 100
Definition: gps.h:103
#define GPS_FIX_3D
3D GPS fix
Definition: gps.h:42
uint8_t fix
status of fix
Definition: gps.h:105
float phi
in radians
float theta
in radians
float psi
in radians
euler angles
enum SPIClockPolarity cpol
clock polarity control
Definition: spi.h:155
enum SPIClockPhase cpha
clock phase control
Definition: spi.h:156
enum SPISlaveSelect select
slave selection behavior
Definition: spi.h:154
SPICallback before_cb
NULL or function called before the transaction.
Definition: spi.h:160
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:161
enum SPIDataSizeSelect dss
data transfer word size
Definition: spi.h:157
volatile uint8_t * output_buf
pointer to transmit buffer for DMA
Definition: spi.h:150
uint16_t input_length
number of data words to read
Definition: spi.h:151
enum SPIClockDiv cdiv
prescaler of main clock to use as SPI clock
Definition: spi.h:159
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition: spi.h:149
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition: spi.h:153
enum SPIBitOrder bitorder
MSB/LSB order.
Definition: spi.h:158
uint16_t output_length
number of data words to write
Definition: spi.h:152
enum SPITransactionStatus status
Definition: spi.h:162
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition: spi_arch.c:533
@ SPICphaEdge1
CPHA = 0.
Definition: spi.h:74
@ SPITransSuccess
Definition: spi.h:99
@ SPITransDone
Definition: spi.h:101
@ SPICpolIdleLow
CPOL = 0.
Definition: spi.h:83
@ SPISelectUnselect
slave is selected before transaction and unselected after
Definition: spi.h:63
@ SPIMSBFirst
Definition: spi.h:112
@ SPIDiv64
Definition: spi.h:125
@ SPIDss8bit
Definition: spi.h:90
SPI transaction structure.
Definition: spi.h:148
static struct FloatEulers * stateGetNedToBodyEulers_f(void)
Get vehicle body attitude euler angles (float).
Definition: state.h:1143
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition: state.h:719
static struct UtmCoor_f * stateGetPositionUtm_f(void)
Get position in UTM coordinates (float).
Definition: state.h:692
static float stateGetHorizontalSpeedNorm_f(void)
Get norm of horizontal ground speed (float).
Definition: state.h:935
static float stateGetHorizontalSpeedDir_f(void)
Get dir of horizontal ground speed (float).
Definition: state.h:944
static struct EnuCoor_f * stateGetSpeedEnu_f(void)
Get ground speed in local ENU coordinates (float).
Definition: state.h:917
@ VECTOR
Definition: guidance_OA.h:52
struct imu_mag_t * imu_get_mag(uint8_t sender_id, bool create)
Find or create the mag in the imu structure.
Definition: imu.c:842
uint8_t abi_id
ABI sensor ID.
Definition: imu.h:80
struct Int32Vect3 scaled
Last scaled values in body frame.
Definition: imu.h:82
Definition: imu.h:79
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
int32_t mag_y
Definition: mag_hmc5843.c:29
int32_t mag_x
Definition: mag_hmc5843.c:29
static void draw_osd(void)
Definition: max7456.c:656
float fz1
Definition: point.c:93
#define SPEED_LOW_PASS_FILTER_STRENGTH
Definition: max7456.c:71
#define BAT_CAPACITY
Definition: max7456.c:76
uint8_t max7456_osd_status
Definition: max7456.c:168
void max7456_periodic(void)
Definition: max7456.c:955
float fx3
Definition: point.c:91
float fx1
Definition: point.c:91
static bool _osd_sprintf(char *buffer, char *string, float value)
Definition: max7456.c:537
static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column)
Definition: max7456.c:474
static void calc_flight_time_left(void)
Definition: max7456.c:403
static void vSubtractVectors(VECTOR *svA, VECTOR svB, VECTOR svC)
Definition: max7456.c:256
static void vMultiplyMatrixByVector(VECTOR *svA, MATRIX smB, VECTOR svC)
Definition: max7456.c:268
float gps_course_deg
Definition: max7456.c:176
float fy2
Definition: point.c:92
float fz2
Definition: point.c:93
uint8_t step
Definition: max7456.c:141
float fy1
Definition: point.c:92
#define OSD_STRING_SIZE
Definition: max7456.c:58
float fy3
Definition: point.c:92
float mag_course_deg
Definition: max7456.c:174
struct spi_transaction max7456_trans
Definition: max7456.c:134
uint8_t osd_enable_val
Definition: max7456.c:170
#define osd_sprintf
Definition: max7456.c:59
float fx
Definition: point.c:85
char osd_str_buf[OSD_STRING_SIZE]
Definition: max7456.c:139
void max7456_init(void)
Definition: max7456.c:926
float fz3
Definition: point.c:93
max7456_osd_status_codes
Definition: max7456.c:145
@ OSD_INIT2
Definition: max7456.c:148
@ OSD_S_STEP1
Definition: max7456.c:153
@ OSD_S_STEP3
Definition: max7456.c:155
@ OSD_FINISHED
Definition: max7456.c:156
@ OSD_S_STEP2
Definition: max7456.c:154
@ OSD_UNINIT
Definition: max7456.c:146
@ OSD_INIT4
Definition: max7456.c:150
@ OSD_IDLE
Definition: max7456.c:152
@ OSD_INIT1
Definition: max7456.c:147
@ OSD_INIT3
Definition: max7456.c:149
@ OSD_READ_STATUS
Definition: max7456.c:151
void max7456_event(void)
Definition: max7456.c:996
float mag_heading_rad
Definition: max7456.c:175
uint32_t max_flyable_distance_left
Definition: max7456.c:172
uint8_t osd_stat_reg
Definition: max7456.c:171
uint8_t osd_attr
Definition: max7456.c:143
float home_dir_deg
Definition: max7456.c:177
static char ascii_to_osd_c(char c)
Definition: max7456.c:358
static void send_mag_heading(struct transport_tx *trans, struct link_device *dev)
Definition: max7456.c:241
float fy
Definition: point.c:86
osd_attributes
Definition: max7456.c:159
@ C_JUST
Definition: max7456.c:164
@ BLINK
Definition: max7456.c:160
@ L_JUST
Definition: max7456.c:162
@ R_JUST
Definition: max7456.c:163
@ INVERT
Definition: max7456.c:161
char osd_string[OSD_STRING_SIZE]
Definition: max7456.c:138
uint8_t osd_enable
Definition: max7456.c:169
uint16_t osd_char_address
Definition: max7456.c:142
#define AMPS_LOW_PASS_FILTER_STRENGTH
Definition: max7456.c:67
float fx2
Definition: point.c:91
char osd_char
Definition: max7456.c:140
uint8_t osd_spi_rx_buffer[2]
Definition: max7456.c:137
uint8_t osd_spi_tx_buffer[2]
Definition: max7456.c:136
float fz
Definition: point.c:87
static float home_direction(void)
Definition: max7456.c:276
Definition: point.c:90
Definition: point.c:84
Maxim MAX7456 single-channel monochrome on-screen display driver.
Maxim MAX7456 single-channel monochrome on-screen display driver.
#define OSD_OSDBL_REG_R
Definition: max7456_regs.h:41
#define OSD_AUTO_INCREMENT_MODE
Definition: max7456_regs.h:56
#define OSD_NVRAM_BUSY_FLAG
Definition: max7456_regs.h:61
#define OSD_VM0_REG
Definition: max7456_regs.h:34
#define OSD_DMM_REG
Definition: max7456_regs.h:36
#define OSD_DMAH_REG
Definition: max7456_regs.h:37
#define OSD_IMAGE_ENABLE
Definition: max7456_regs.h:48
#define OSD_DMAL_REG
Definition: max7456_regs.h:38
#define OSD_BLINK_CHAR
Definition: max7456_regs.h:53
#define OSD_OSDBL_REG
Definition: max7456_regs.h:40
#define OSD_RESET_BUSY_FLAG
Definition: max7456_regs.h:60
#define OSD_RESET
Definition: max7456_regs.h:50
#define OSD_INVERT_PIXELS
Definition: max7456_regs.h:54
#define OSD_VIDEO_MODE_PAL
Definition: max7456_regs.h:45
#define OSD_STAT_REG
Definition: max7456_regs.h:42
float waypoint_get_x(uint8_t wp_id)
Get X/East coordinate of waypoint in meters.
Definition: waypoints.c:97
float waypoint_get_y(uint8_t wp_id)
Get Y/North coordinate of waypoint in meters.
Definition: waypoints.c:105
#define GetPosAlt()
Get current altitude above MSL.
Definition: nav.h:232
#define GetAltRef()
Get current altitude reference for local coordinates.
Definition: nav.h:241
static uint32_t idx
#define MAX_PPRZ
Definition: paparazzi.h:8
float y
in meters
float x
in meters
float alt
in meters (above WGS84 reference ellipsoid or above MSL)
float z
in meters
vector in East North Up coordinates Units: meters
Rotorcraft navigation functions.
Architecture independent SPI (Serial Peripheral Interface) API.
int32_t stabilization_cmd[COMMANDS_NB]
Stabilization commands.
Definition: stabilization.c:34
API to get/set the generic vehicle states.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
Architecture independent timing functions.
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
short int16_t
Typedef defining 16 bit short type.
Definition: vl53l1_types.h:93
unsigned long long uint64_t
Definition: vl53l1_types.h:72
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
signed char int8_t
Typedef defining 8 bit char type.
Definition: vl53l1_types.h:103