Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
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
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"
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
109typedef struct {
110 float fx;
111 float fy;
112 float fz;
113} VECTOR;
114
115typedef 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)
122static void mag_compass(void);
123#endif
124static void send_mag_heading(struct transport_tx *trans, struct link_device *dev);
127static float home_direction(void);
128static char ascii_to_osd_c(char c);
129static void calc_flight_time_left(void);
130static void draw_osd(void);
131static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column);
132static bool _osd_sprintf(char *buffer, char *string, float value);
133
135
140char osd_char = ' ';
144
158
167
173
177float home_dir_deg = 0;
178
179#if defined(FIXEDWING_FIRMWARE)
180// Periodic function called with a frequency defined in the module .xml file
181void mag_compass(void)
182{
183
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
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
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)
216#else
217 if (gps.fix == GPS_FIX_3D && stateGetHorizontalSpeedNorm_f() > 10.0) {
218#endif
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); }
226 }
227 }
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
234 if (mag_course_deg < 0) { mag_course_deg += 360; }
235
236 return;
237}
238#endif
239
240
241static void send_mag_heading(struct transport_tx *trans, struct link_device *dev)
242{
244#if DOWNLINK
246#endif
247
248 return;
249}
250
251//*******************************************************************
252// function name: vSubtractVectors
253// description: subtracts two vectors a = b - c
254// parameters:
255//*******************************************************************
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//*******************************************************************
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
276static float home_direction(void)
277{
278
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
297#if defined(FIXEDWING_FIRMWARE)
301#else
304 Home_Position.fz = 0;
305#endif
306
307 /* distance between plane and object */
309
310 /* yaw */
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
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*/
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
358static 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
403static 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
412 bat_capacity_used += (current_amps * 1000.) / (3600. * (float)MAX7456_PERIODIC_FREQ);
414 if (bat_capacity_left < 0) { bat_capacity_left = 0; }
416
417#if defined(FIXEDWING_FIRMWARE)
418 if (stateGetHorizontalSpeedNorm_f() < 5.0 || autopilot.launch == false) {
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
437
441
442#else
443
446 static uint64_t current_amps_sum = 0;
450
451 // LOW PASS FILTERS for making the OSD 'max_flyable_distance_left' var change more gently.
454
458
462
465
466#endif
467
469
470 return;
471}
472
473
475{
476
477 int8_t x = 0, idx = 0, post_offset = 0, aft_offset = 0, string_len = 0;
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++; }
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
523//TRIGGER THE SPI TRANSFERS. The rest of the spi transfers occur in the "max7456_event" function.
527 max7456_trans.output_buf[1] = (uint8_t)((osd_char_address >> 8) & 0x0001);
530
531 }
532
533 return;
534}
535
536
537static bool _osd_sprintf(char *buffer, char *string, float value)
538{
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};
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
656void 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
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;
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
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
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
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)
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
780 osd_sprintf(osd_string, "STALL!", 0);
781 osd_put_s(osd_string, (R_JUST | BLINK), 6, 1, 30);
782 } else {
784 osd_put_s(osd_string, R_JUST, 6, 1, 30);
785 }
786#else
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
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) {
814 } else {
816 }
817#else
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
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
861#endif
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
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.
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.
981 } else if (max7456_osd_status == OSD_INIT2) {
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
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));
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
1028 break;
1029 case (OSD_S_STEP1):
1035 break;
1036 case (OSD_S_STEP2):
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) {
1049 } else {
1050 max7456_trans.output_buf[0] = 0xFF; //Exit the auto increment mode
1053 }
1054 break;
1055 case (OSD_FINISHED):
1061 break;
1062 case (OSD_READ_STATUS):
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
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:44
#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
#define AP_MODE_AUTO2
#define AP_MODE_AUTO1
Some architecture independent helper functions for GPIOs.
struct GpsState gps
global GPS state
Definition gps.c:74
int32_t course
GPS course over ground in rad*1e7, [0, 2*Pi]*1e7 (CW/north)
Definition gps.h:99
uint16_t pdop
position dilution of precision scaled by 100
Definition gps.h:105
#define GPS_FIX_3D
3D GPS fix
Definition gps.h:44
uint8_t fix
status of fix
Definition gps.h:107
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:1306
static struct UtmCoor_f * stateGetPositionUtm_f(void)
Get position in UTM coordinates (float).
Definition state.h:821
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition state.h:848
static float stateGetHorizontalSpeedNorm_f(void)
Get norm of horizontal ground speed (float).
Definition state.h:1076
static float stateGetHorizontalSpeedDir_f(void)
Get dir of horizontal ground speed (float).
Definition state.h:1085
static struct EnuCoor_f * stateGetSpeedEnu_f(void)
Get ground speed in local ENU coordinates (float).
Definition state.h:1058
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:931
uint8_t abi_id
ABI sensor ID.
Definition imu.h:80
struct Int32Vect3 scaled
Last scaled values in body frame.
Definition imu.h:82
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
uint16_t foo
Definition main_demo5.c:58
static void draw_osd(void)
Definition max7456.c:656
#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
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
uint8_t step
Definition max7456.c:141
#define OSD_STRING_SIZE
Definition max7456.c:58
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
char osd_str_buf[OSD_STRING_SIZE]
Definition max7456.c:139
void max7456_init(void)
Definition max7456.c:926
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
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
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
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
#define OSD_AUTO_INCREMENT_MODE
#define OSD_NVRAM_BUSY_FLAG
#define OSD_VM0_REG
#define OSD_DMM_REG
#define OSD_DMAH_REG
#define OSD_IMAGE_ENABLE
#define OSD_DMAL_REG
#define OSD_BLINK_CHAR
#define OSD_OSDBL_REG
#define OSD_RESET_BUSY_FLAG
#define OSD_RESET
#define OSD_INVERT_PIXELS
#define OSD_VIDEO_MODE_PAL
#define OSD_STAT_REG
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:233
#define GetAltRef()
Get current altitude reference for local coordinates.
Definition nav.h:242
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.
struct Stabilization stabilization
int32_t cmd[COMMANDS_NB]
output command vector, range from [-MAX_PPRZ:MAX_PPRZ] (store for messages)
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.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
short int16_t
Typedef defining 16 bit short type.
unsigned long long uint64_t
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
signed char int8_t
Typedef defining 8 bit char type.