Paparazzi UAS  v5.14.0_stable-0-g3f680d1
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
max7456.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 Chris
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 "mcu_periph/sys_time.h"
32 #include "mcu_periph/gpio.h"
33 #include "mcu_periph/spi.h"
34 
35 #include "generated/flight_plan.h"
36 #include "generated/airframe.h"
37 #include "autopilot.h"
38 #include "subsystems/electrical.h"
39 #include "state.h"
40 
41 // for GetPosAlt, include correct header until we have unified API
42 #ifdef AP
43 #include "subsystems/navigation/nav.h"
44 #else
46 #endif
47 
48 // Peripherials
51 
52 #define OSD_STRING_SIZE 31
53 #define osd_sprintf _osd_sprintf
54 
55 static char ascii_to_osd_c(char c);
56 static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column);
57 static bool _osd_sprintf(char *buffer, char *string, float value);
58 
60 
65 char osd_char = ' ';
68 uint8_t osd_attr = false;
69 
82 };
83 
87 };
88 
93 bool osd_stat_reg_valid = false;
94 
95 void max7456_init(void)
96 {
97 
98  max7456_trans.slave_idx = MAX7456_SLAVE_IDX;
109  max7456_trans.before_cb = NULL;
110  max7456_trans.after_cb = NULL;
111 
112  osd_enable = 1;
115 
116  return;
117 }
118 
120 {
121 
122  float temp = 0;
123 //This code is executed always and checks if the "osd_enable" var has been changed by telemetry.
124 //If yes then it commands a reset but this time turns on or off the osd overlay, not the video.
125  if (max7456_osd_status == OSD_IDLE) {
126  if (osd_enable > 1) {
127  osd_enable = 1;
128  }
129  if ((osd_enable << 3) != osd_enable_val) {
130  osd_enable_val = (osd_enable << 3);
132  }
133  }
134 
135  //INITIALIZATION OF THE OSD
137  step = 0;
140  //This operation needs at least 100us but when the periodic function will be invoked again
141  //sufficient time will have elapsed even with at a periodic frequency of 1000 Hz
144  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
145  } else if (max7456_osd_status == OSD_INIT2) {
150  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
151  } else if (max7456_osd_status == OSD_IDLE && osd_enable > 0) { // DRAW THE OSD SCREEN
152  //draw_osd();
153  switch (step) {
154  case (0):
155  osd_put_s("HDG", FALSE, 3, 0, 13);
156  step = 10;
157  break;
158  case (10):
159  temp = ((float)electrical.vsupply) / 10;
160  osd_sprintf(osd_string, "%.1fV", temp);
161  if (temp > LOW_BAT_LEVEL) {
162  osd_put_s(osd_string, FALSE, 8, 0, 2);
163  } else {
164  osd_put_s(osd_string, BLINK | INVERT, 8, 0, 2);
165  }
166  step = 20;
167  break;
168  case (20):
169 #if MAG_HEADING_AVAILABLE && !defined(SITL)
170  temp = DegOfRad(MAG_Heading);
171  if (temp < 0) {
172  temp += 360;
173  }
174 #else
175  temp = DegOfRad(state.h_speed_dir_f);
176  if (temp < 0) {
177  temp += 360;
178  }
179 #endif
180  osd_sprintf(osd_string, "%.0f", temp);
181  osd_put_s(osd_string, FALSE, 8, 1, 13);
182  step = 30;
183  break;
184  case (30):
185  osd_sprintf(osd_string, "%.0fKm", (state.h_speed_norm_f * 3.6));
186  osd_put_s(osd_string, FALSE, 8, 0, 24);
187  step = 40;
188  break;
189  case (40):
190  osd_sprintf(osd_string, "%.0fm", GetPosAlt());
191  osd_put_s(osd_string, FALSE, 10, 13, 2);
192  step = 50;
193  break;
194  case (50):
195  osd_sprintf(osd_string, "%.1fVZ", stateGetSpeedEnu_f()->z);
196  osd_put_s(osd_string, FALSE, 7, 13, 24);
197  step = 10;
198  break;
199  default: break;
200  }
201  }
202  return;
203 }
204 
205 void max7456_event(void)
206 {
207 
208  static uint8_t x = 0;
209 
212 
213  switch (max7456_osd_status) {
214  case (OSD_INIT1):
216  break;
217  case (OSD_INIT3):
221  max7456_trans.output_buf[1] = max7456_trans.input_buf[0] & (~(1 << 4));
223  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
224  break;
225  case (OSD_INIT4):
227 #if USE_PAL_FOR_OSD_VIDEO
229 #else
231 #endif
233  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
234  break;
235  case (OSD_READ_STATUS):
237  osd_stat_reg_valid = true;
239  break;
240  case (OSD_S_STEP1):
245  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
246  break;
247  case (OSD_S_STEP2):
252  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
253  x = 0;
254  break;
255  case (OSD_S_STEP3):
256  max7456_trans.output_length = 1; //1 byte tranfers, auto address incrementing.
257  if (osd_string[x] != 0XFF) {
259  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
260  } else {
261  max7456_trans.output_buf[0] = 0xFF; //Exit the auto increment mode
263  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
264  }
265  break;
266  case (OSD_FINISHED):
267  osd_attr = 0;
270  break;
271  default: break;
272  }
273  }
274  return;
275 }
276 
277 static char ascii_to_osd_c(char c)
278 {
279 
280  if (c >= '0' && c <= '9') {
281  if (c == '0') {
282  c -= 38;
283  } else {
284  c -= 48;
285  }
286  } else {
287  if (c >= 'A' && c <= 'Z') {
288  c -= 54;
289  } else {
290  if (c >= 'a' && c <= 'z') {
291  c -= 60;
292  } else {
293  switch (c) {
294  case ('('): c = 0x3f; break;
295  case (')'): c = 0x40; break;
296  case ('.'): c = 0x41; break;
297  case ('?'): c = 0x42; break;
298  case (';'): c = 0x43; break;
299  case (':'): c = 0x44; break;
300  case (','): c = 0x45; break;
301  //case('''): c = 0x46; break;
302  case ('/'): c = 0x47; break;
303  case ('"'): c = 0x48; break;
304  case ('-'): c = 0x49; break;
305  case ('<'): c = 0x4A; break;
306  case ('>'): c = 0x4B; break;
307  case ('@'): c = 0x4C; break;
308  case (' '): c = 0x00; break;
309  case ('\0'): c = 0xFF; break;
310  default : break;
311  }
312  }
313  }
314  }
315  return (c);
316 }
317 
318 static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column)
319 {
320 
321  uint8_t x = 0;
322 
323  if (row > 15) {
324  column = 15;
325  }
326  if (column > 29) {
327  column = 29;
328  }
329  osd_char_address = ((uint16_t)row * 30) + column;
330 
331  // translate the string and put it to the "osd_string" '\0' = 0xff
332  x = 0;
333  while ( (*(string + x) != '\0') && ( x < (sizeof(osd_string)-1) )) {
334  osd_string[x] = ascii_to_osd_c(*(string + x));
335  x++;
336  }
337  osd_string[x] = ascii_to_osd_c(*(string + x));
338 
339  for (x = 0; x < sizeof(osd_string); x++) {
340  if (osd_string[x] == 0xff) {
341  break;
342  }
343  }
344 
345  // Prevent overflow condition
346  if (char_nb >= OSD_STRING_SIZE) {
347  char_nb = OSD_STRING_SIZE-1;
348  }
349  //Adjust for the reserved character number.
350  for (; x < char_nb; x++) {
351  osd_string[x] = 0;
352  }
353  osd_string[x] = 0xff;
354 
355  osd_attr = attributes;
356 
357  //TRIGGER THE SPI TRANSFERS. The rest of the spi transfers occur in the "max7456_event" function.
358  if (max7456_osd_status == OSD_IDLE) {
361  max7456_trans.output_buf[1] = (uint8_t)((osd_char_address >> 8) & 0x0001);
363  spi_submit(&(MAX7456_SPI_DEV), &max7456_trans);
364  }
365  return;
366 }
367 
368 // A VERY VERY STRIPED DOWN sprintf function suitable only for the paparazzi OSD.
369 static bool _osd_sprintf(char *buffer, char *string, float value)
370 {
371 
372  uint8_t param_start = 0;
373  uint8_t param_end = 0;
374  uint8_t frac_nb = 0;
375  uint8_t digit = 0;
376  uint8_t x = 0, y = 0, z = 0;
377 
378  uint16_t i_dec = 0;
379  uint16_t i_frac = 0;
380 
381  char to_asc[10] = {48, 48, 48, 48, 48, 48, 48, 48, 48, 48};
382 
383  // Clear the osd string.
384  for (x = 0; x < sizeof(osd_string); x++) {
385  osd_string[x] = 0;
386  }
387  x = 0;
388  // Search for the prameter start and stop positions.
389  while (*(string + x) != '\0') {
390  if (*(string + x) == '%') {
391  param_start = x;
392  } else if (*(string + x) == 'f') {
393  param_end = x;
394  break;
395  }
396  x++;
397  }
398  // find and bound the precision specified.
399  frac_nb = *(string + param_end - 1) - 48; // Convert to number, ASCII 48 = '0'
400  if (frac_nb > 3) {
401  frac_nb = 3; // Bound value.
402  }
403  // Point y to one before the end of the array
404  // Because we will increment it with frac_nb-1, so pointing it to the end would result in overflow
405  y = (sizeof(to_asc) - 3);
406  i_dec = abs((int16_t)value);
407  // Fist we will deal with the fractional part if specified.
408  if (frac_nb > 0 && frac_nb <= 3) {
409  i_frac = abs((int16_t)((value - (int16_t)value) * 1000)); // Max precision is 3 digits.
410  x = 100;
411  z = frac_nb;
412  do { // Example if frac_nb=2 then 952 will show as .95
413  z--;
414  digit = (i_frac / x);
415  to_asc[y + z] = digit + 48; // Convert to ASCII
416  i_frac -= digit * x; // Calculate the remainder.
417  x /= 10; // 952-(9*100) = 52, 52-(10*5)=2 etc.
418  } while (z > 0);
419  y -= frac_nb; // set y to point where the dot must be placed.
420  to_asc[y] = '.';
421  y--; // Set y to point where the rest of the numbers must be written.
422  }
423 
424  // Now it is time for the integer part. "y" already points to the position just before the dot.
425  do {
426  to_asc[y] = (i_dec % 10) + 48; //Write at least one digit even if value is zero.
427  i_dec /= 10;
428  if (i_dec <= 0) { // This way the leading zero is ommited.
429  if (value < 0) {
430  y--; to_asc[y] = '-'; // Place the minus sign if needed.
431  }
432  break;
433  } else {
434  y--;
435  }
436  } while (1);
437 
438  // Fill the buffer with the characters in the beggining of the string if any.
439  for (x = 0; x < param_start; x++) {
440  *(buffer + x) = *(string + x);
441  }
442 
443  // x is now pointing to the next character in osd_string.
444  // y is already pointing to the first digit or negative sign in "to_asc" array.
445  while (y < sizeof(to_asc)) {
446  *(buffer + x) = to_asc[y];
447  x++; y++;
448  }
449  // x is now pointing to the next character in osd_string.
450  // "param_end" is pointing to the last format character in the string.
451  do {
452  param_end++;
453  *(buffer + x++) = *(string + param_end);
454  } while (*(string + param_end) != '\0'); //Write the rest of the string including the terminating char.
455 
456  return (0);
457 }
max7456_osd_status_codes
Definition: max7456.c:70
unsigned short uint16_t
Definition: types.h:16
enum SPIClockPolarity cpol
clock polarity control
Definition: spi.h:149
char osd_char
Definition: max7456.c:65
char osd_str_buf[OSD_STRING_SIZE]
Definition: max7456.c:64
enum SPIClockDiv cdiv
prescaler of main clock to use as SPI clock
Definition: spi.h:153
uint16_t output_length
number of data words to write
Definition: spi.h:146
#define OSD_BLINK_CHAR
Definition: max7456_regs.h:53
Maxim MAX7456 single-channel monochrome on-screen display driver.
float h_speed_dir_f
Direction of horizontal ground speed.
Definition: state.h:321
#define LOW_BAT_LEVEL
low battery level in Volts (for 3S LiPo)
Definition: electrical.h:36
Some architecture independent helper functions for GPIOs.
void max7456_init(void)
Definition: max7456.c:95
bool osd_stat_reg_valid
Definition: max7456.c:93
float h_speed_norm_f
Norm of horizontal ground speed.
Definition: state.h:315
Maxim MAX7456 single-channel monochrome on-screen display driver.
SPI transaction structure.
Definition: spi.h:142
osd_attributes
Definition: max7456.c:84
bool spi_submit(struct spi_periph *p, struct spi_transaction *t)
Submit SPI transaction.
Definition: spi_arch.c:458
#define OSD_DMM_REG
Definition: max7456_regs.h:36
enum SPIBitOrder bitorder
MSB/LSB order.
Definition: spi.h:152
#define OSD_DMAH_REG
Definition: max7456_regs.h:37
#define OSD_IMAGE_ENABLE
Definition: max7456_regs.h:48
volatile uint8_t * output_buf
pointer to transmit buffer for DMA
Definition: spi.h:144
enum SPISlaveSelect select
slave selection behavior
Definition: spi.h:148
#define OSD_RESET
Definition: max7456_regs.h:50
#define FALSE
Definition: std.h:5
#define osd_sprintf
Definition: max7456.c:53
Architecture independent SPI (Serial Peripheral Interface) API.
#define OSD_AUTO_INCREMENT_MODE
Definition: max7456_regs.h:56
void max7456_event(void)
Definition: max7456.c:205
enum SPIClockPhase cpha
clock phase control
Definition: spi.h:150
uint8_t osd_stat_reg
Definition: max7456.c:92
#define OSD_OSDBL_REG_R
Definition: max7456_regs.h:41
#define OSD_OSDBL_REG
Definition: max7456_regs.h:40
struct spi_transaction max7456_trans
Definition: max7456.c:59
Definition: spi.h:84
static bool _osd_sprintf(char *buffer, char *string, float value)
Definition: max7456.c:369
Interface for electrical status: supply voltage, current, battery status, etc.
Architecture independent timing functions.
SPICallback after_cb
NULL or function called after the transaction.
Definition: spi.h:155
char osd_string[OSD_STRING_SIZE]
Definition: max7456.c:63
signed short int16_t
Definition: types.h:17
uint8_t osd_attr
Definition: max7456.c:68
CPOL = 0.
Definition: spi.h:77
uint8_t step
Definition: max7456.c:66
Definition: max7456.c:86
uint16_t input_length
number of data words to read
Definition: spi.h:145
#define OSD_DMAL_REG
Definition: max7456_regs.h:38
#define OSD_VM0_REG
Definition: max7456_regs.h:34
uint8_t max7456_osd_status
Definition: max7456.c:89
Core autopilot interface common to all firmwares.
Rotorcraft navigation functions.
#define OSD_INVERT_PIXELS
Definition: max7456_regs.h:54
static void osd_put_s(char *string, uint8_t attributes, uint8_t char_nb, uint8_t row, uint8_t column)
Definition: max7456.c:318
#define OSD_VIDEO_MODE_PAL
Definition: max7456_regs.h:45
unsigned char uint8_t
Definition: types.h:14
API to get/set the generic vehicle states.
void max7456_periodic(void)
Definition: max7456.c:119
static struct EnuCoor_f * stateGetSpeedEnu_f(void)
Get ground speed in local ENU coordinates (float).
Definition: state.h:917
CPHA = 0.
Definition: spi.h:68
uint16_t vsupply
supply voltage in decivolts
Definition: electrical.h:48
#define OSD_STRING_SIZE
Definition: max7456.c:52
uint8_t osd_enable_val
Definition: max7456.c:91
slave is selected before transaction and unselected after
Definition: spi.h:57
enum SPIDataSizeSelect dss
data transfer word size
Definition: spi.h:151
uint8_t slave_idx
slave id: SPI_SLAVE0 to SPI_SLAVE4
Definition: spi.h:147
uint8_t osd_spi_tx_buffer[2]
Definition: max7456.c:61
Definition: spi.h:119
volatile uint8_t * input_buf
pointer to receive buffer for DMA
Definition: spi.h:143
SPICallback before_cb
NULL or function called before the transaction.
Definition: spi.h:154
uint8_t osd_enable
Definition: max7456.c:90
struct Electrical electrical
Definition: electrical.c:65
uint16_t osd_char_address
Definition: max7456.c:67
Definition: max7456.c:85
uint8_t osd_spi_rx_buffer[2]
Definition: max7456.c:62
struct State state
Definition: state.c:36
enum SPITransactionStatus status
Definition: spi.h:156
static char ascii_to_osd_c(char c)
Definition: max7456.c:277