2 ******************************************************************************
3 * @addtogroup OpenPilotModules OpenPilot Modules
5 * @addtogroup OSDgenModule osdgen Module
6 * @brief Process OSD information
10 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
11 * @brief OSD gen module, handles OSD draw. Parts from CL-OSD and SUPEROSD projects
12 * @see The GNU Public License (GPL) Version 3
14 *****************************************************************************/
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 3 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 * You should have received a copy of the GNU General Public License along
27 * with this program; if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include <openpilot.h>
37 #include "attitudestate.h"
38 #include "gpspositionsensor.h"
39 #include "homelocation.h"
41 #include "gpssatellites.h"
42 #include "osdsettings.h"
43 #include "barosensor.h"
45 #include "flightstatus.h"
48 #include "font12x18.h"
50 #include "WMMInternal.h"
54 static uint16_t angleA=0;
55 static int16_t angleB=90;
56 static int16_t angleC=0;
59 static int16_t m_pitch=0;
60 static int16_t m_roll=0;
61 static int16_t m_yaw=0;
62 static int16_t m_batt=0;
63 static int16_t m_alt=0;
65 static uint8_t m_gpsStatus=0;
66 static int32_t m_gpsLat=0;
67 static int32_t m_gpsLon=0;
68 static float m_gpsAlt=0;
69 static float m_gpsSpd=0;*/
71 extern uint8_t *draw_buffer_level
;
72 extern uint8_t *draw_buffer_mask
;
73 extern uint8_t *disp_buffer_level
;
74 extern uint8_t *disp_buffer_mask
;
81 static void osdgenTask(void *parameters
);
85 #define LONG_TIME 0xffff
86 xSemaphoreHandle osdSemaphore
= NULL
;
88 #define STACK_SIZE_BYTES 4096
90 #define TASK_PRIORITY (tskIDLE_PRIORITY + 4)
91 #define UPDATE_PERIOD 100
96 static xTaskHandle osdgenTaskHandle
;
99 unsigned int width
, height
;
100 const uint16_t *level
;
101 const uint16_t *mask
;
104 struct splashEntry splash
[3] = {
119 uint16_t mirror(uint16_t source
)
121 int result
= ((source
& 0x8000) >> 7) | ((source
& 0x4000) >> 5) | ((source
& 0x2000) >> 3) | ((source
& 0x1000) >> 1) | ((source
& 0x0800) << 1)
122 | ((source
& 0x0400) << 3) | ((source
& 0x0200) << 5) | ((source
& 0x0100) << 7) | ((source
& 0x0080) >> 7) | ((source
& 0x0040) >> 5)
123 | ((source
& 0x0020) >> 3) | ((source
& 0x0010) >> 1) | ((source
& 0x0008) << 1) | ((source
& 0x0004) << 3) | ((source
& 0x0002) << 5)
124 | ((source
& 0x0001) << 7);
131 memset((uint8_t *)draw_buffer_mask
, 0, GRAPHICS_WIDTH
* GRAPHICS_HEIGHT
);
132 memset((uint8_t *)draw_buffer_level
, 0, GRAPHICS_WIDTH
* GRAPHICS_HEIGHT
);
135 void copyimage(uint16_t offsetx
, uint16_t offsety
, int image
)
137 // check top/left position
138 if (!validPos(offsetx
, offsety
)) {
141 struct splashEntry splash_info
;
142 splash_info
= splash
[image
];
143 offsetx
= offsetx
/ 8;
144 for (uint16_t y
= offsety
; y
< ((splash_info
.height
) + offsety
); y
++) {
145 uint16_t x1
= offsetx
;
146 for (uint16_t x
= offsetx
; x
< (((splash_info
.width
) / 16) + offsetx
); x
++) {
147 draw_buffer_level
[y
* GRAPHICS_WIDTH
+ x1
+ 1] = (uint8_t)(
148 mirror(splash_info
.level
[(y
- offsety
) * ((splash_info
.width
) / 16) + (x
- offsetx
)]) >> 8);
149 draw_buffer_level
[y
* GRAPHICS_WIDTH
+ x1
] = (uint8_t)(
150 mirror(splash_info
.level
[(y
- offsety
) * ((splash_info
.width
) / 16) + (x
- offsetx
)]) & 0xFF);
151 draw_buffer_mask
[y
* GRAPHICS_WIDTH
+ x1
+ 1] = (uint8_t)(
152 mirror(splash_info
.mask
[(y
- offsety
) * ((splash_info
.width
) / 16) + (x
- offsetx
)]) >> 8);
153 draw_buffer_mask
[y
* GRAPHICS_WIDTH
+ x1
] = (uint8_t)(mirror(splash_info
.mask
[(y
- offsety
) * ((splash_info
.width
) / 16) + (x
- offsetx
)]) & 0xFF);
159 uint8_t validPos(uint16_t x
, uint16_t y
)
161 if (x
< GRAPHICS_HDEADBAND
|| x
>= GRAPHICS_WIDTH_REAL
|| y
>= GRAPHICS_HEIGHT_REAL
) {
167 // Credit for this one goes to wikipedia! :-)
168 void drawCircle(uint16_t x0
, uint16_t y0
, uint16_t radius
)
172 int ddF_y
= -2 * radius
;
176 write_pixel_lm(x0
, y0
+ radius
, 1, 1);
177 write_pixel_lm(x0
, y0
- radius
, 1, 1);
178 write_pixel_lm(x0
+ radius
, y0
, 1, 1);
179 write_pixel_lm(x0
- radius
, y0
, 1, 1);
182 // ddF_x == 2 * x + 1;
184 // f == x*x + y*y - radius*radius + 2*x - y + 1;
193 write_pixel_lm(x0
+ x
, y0
+ y
, 1, 1);
194 write_pixel_lm(x0
- x
, y0
+ y
, 1, 1);
195 write_pixel_lm(x0
+ x
, y0
- y
, 1, 1);
196 write_pixel_lm(x0
- x
, y0
- y
, 1, 1);
197 write_pixel_lm(x0
+ y
, y0
+ x
, 1, 1);
198 write_pixel_lm(x0
- y
, y0
+ x
, 1, 1);
199 write_pixel_lm(x0
+ y
, y0
- x
, 1, 1);
200 write_pixel_lm(x0
- y
, y0
- x
, 1, 1);
204 void swap(uint16_t *a
, uint16_t *b
)
212 static const int8_t sinData
[91] =
213 { 0, 2, 3, 5, 7, 9, 10, 12, 14, 16, 17, 19, 21, 22, 24, 26, 28, 29, 31, 33, 34, 36, 37, 39, 41, 42, 44, 45, 47, 48, 50, 52, 53, 54, 56, 57, 59, 60, 62, 63, 64,
214 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 87, 88, 89, 90, 91, 91, 92, 93, 93, 94, 95, 95, 96, 96, 97, 97, 97, 98,
215 98, 98, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100 };
217 static int8_t mySin(uint16_t angle
)
223 // 180-359 is same as 0-179 but negative.
228 // 0-89 is equal to 90-179 except backwards.
232 return mult
* (int8_t)(sinData
[pos
]);
235 static int8_t myCos(uint16_t angle
)
237 return mySin(angle
+ 90);
240 /// Draws four points relative to the given center point.
242 /// \li centerX + X, centerY + Y
243 /// \li centerX + X, centerY - Y
244 /// \li centerX - X, centerY + Y
245 /// \li centerX - X, centerY - Y
247 /// \param centerX the x coordinate of the center point
248 /// \param centerY the y coordinate of the center point
249 /// \param deltaX the difference between the centerX coordinate and each pixel drawn
250 /// \param deltaY the difference between the centerY coordinate and each pixel drawn
251 /// \param color the color to draw the pixels with.
252 void plotFourQuadrants(int32_t centerX
, int32_t centerY
, int32_t deltaX
, int32_t deltaY
)
254 write_pixel_lm(centerX
+ deltaX
, centerY
+ deltaY
, 1, 1); // Ist Quadrant
255 write_pixel_lm(centerX
- deltaX
, centerY
+ deltaY
, 1, 1); // IInd Quadrant
256 write_pixel_lm(centerX
- deltaX
, centerY
- deltaY
, 1, 1); // IIIrd Quadrant
257 write_pixel_lm(centerX
+ deltaX
, centerY
- deltaY
, 1, 1); // IVth Quadrant
260 /// Implements the midpoint ellipse drawing algorithm which is a bresenham
263 /// \param centerX the x coordinate of the center of the ellipse
264 /// \param centerY the y coordinate of the center of the ellipse
265 /// \param horizontalRadius the horizontal radius of the ellipse
266 /// \param verticalRadius the vertical radius of the ellipse
267 /// \param color the color of the ellipse border
268 void ellipse(int centerX
, int centerY
, int horizontalRadius
, int verticalRadius
)
270 int64_t doubleHorizontalRadius
= horizontalRadius
* horizontalRadius
;
271 int64_t doubleVerticalRadius
= verticalRadius
* verticalRadius
;
273 int64_t error
= doubleVerticalRadius
- doubleHorizontalRadius
* verticalRadius
+ (doubleVerticalRadius
>> 2);
276 int y
= verticalRadius
;
278 int deltaY
= (doubleHorizontalRadius
<< 1) * y
;
280 plotFourQuadrants(centerX
, centerY
, x
, y
);
282 while (deltaY
>= deltaX
) {
284 deltaX
+= (doubleVerticalRadius
<< 1);
286 error
+= deltaX
+ doubleVerticalRadius
;
290 deltaY
-= (doubleHorizontalRadius
<< 1);
294 plotFourQuadrants(centerX
, centerY
, x
, y
);
297 error
= (int64_t)(doubleVerticalRadius
* (x
+ 1 / 2.0f
) * (x
+ 1 / 2.0f
) + doubleHorizontalRadius
* (y
- 1) * (y
- 1) - doubleHorizontalRadius
* doubleVerticalRadius
);
300 error
+= doubleHorizontalRadius
;
302 deltaY
-= (doubleHorizontalRadius
<< 1);
307 deltaX
+= (doubleVerticalRadius
<< 1);
311 plotFourQuadrants(centerX
, centerY
, x
, y
);
315 void drawArrow(uint16_t x
, uint16_t y
, uint16_t angle
, uint16_t size
)
317 int16_t a
= myCos(angle
);
318 int16_t b
= mySin(angle
);
320 a
= (a
* (size
/ 2)) / 100;
321 b
= (b
* (size
/ 2)) / 100;
322 write_line_lm((x
) - 1 - b
, (y
) - 1 + a
, (x
) - 1 + b
, (y
) - 1 - a
, 1, 1); // Direction line
323 // write_line_lm((GRAPHICS_SIZE/2)-1 + a/2, (GRAPHICS_SIZE/2)-1 + b/2, (GRAPHICS_SIZE/2)-1 - a/2, (GRAPHICS_SIZE/2)-1 - b/2, 1, 1); //Arrow bottom line
324 write_line_lm((x
) - 1 + b
, (y
) - 1 - a
, (x
) - 1 - a
/ 2, (y
) - 1 - b
/ 2, 1, 1); // Arrow "wings"
325 write_line_lm((x
) - 1 + b
, (y
) - 1 - a
, (x
) - 1 + a
/ 2, (y
) - 1 + b
/ 2, 1, 1);
328 void drawBox(uint16_t x1
, uint16_t y1
, uint16_t x2
, uint16_t y2
)
330 write_line_lm(x1
, y1
, x2
, y1
, 1, 1); // top
331 write_line_lm(x1
, y1
, x1
, y2
, 1, 1); // left
332 write_line_lm(x2
, y1
, x2
, y2
, 1, 1); // right
333 write_line_lm(x1
, y2
, x2
, y2
, 1, 1); // bottom
338 // SUPEROSD routines, modified
341 * write_pixel: Write a pixel at an x,y position to a given surface.
343 * @param buff pointer to buffer to write in
344 * @param x x coordinate
345 * @param y y coordinate
346 * @param mode 0 = clear bit, 1 = set bit, 2 = toggle bit
348 void write_pixel(uint8_t *buff
, unsigned int x
, unsigned int y
, int mode
)
351 // Determine the bit in the word to be set and the word
352 // index to set it in.
353 int bitnum
= CALC_BIT_IN_WORD(x
);
354 int wordnum
= CALC_BUFF_ADDR(x
, y
);
356 uint16_t mask
= 1 << (7 - bitnum
);
357 WRITE_WORD_MODE(buff
, wordnum
, mask
, mode
);
361 * write_pixel_lm: write the pixel on both surfaces (level and mask.)
362 * Uses current draw buffer.
364 * @param x x coordinate
365 * @param y y coordinate
366 * @param mmode 0 = clear, 1 = set, 2 = toggle
367 * @param lmode 0 = black, 1 = white, 2 = toggle
369 void write_pixel_lm(unsigned int x
, unsigned int y
, int mmode
, int lmode
)
372 // Determine the bit in the word to be set and the word
373 // index to set it in.
374 int bitnum
= CALC_BIT_IN_WORD(x
);
375 int wordnum
= CALC_BUFF_ADDR(x
, y
);
377 uint16_t mask
= 1 << (7 - bitnum
);
378 WRITE_WORD_MODE(draw_buffer_mask
, wordnum
, mask
, mmode
);
379 WRITE_WORD_MODE(draw_buffer_level
, wordnum
, mask
, lmode
);
383 * write_hline: optimised horizontal line writing algorithm
385 * @param buff pointer to buffer to write in
386 * @param x0 x0 coordinate
387 * @param x1 x1 coordinate
388 * @param y y coordinate
389 * @param mode 0 = clear, 1 = set, 2 = toggle
391 void write_hline(uint8_t *buff
, unsigned int x0
, unsigned int x1
, unsigned int y
, int mode
)
401 /* This is an optimised algorithm for writing horizontal lines.
402 * We begin by finding the addresses of the x0 and x1 points. */
403 int addr0
= CALC_BUFF_ADDR(x0
, y
);
404 int addr1
= CALC_BUFF_ADDR(x1
, y
);
405 int addr0_bit
= CALC_BIT_IN_WORD(x0
);
406 int addr1_bit
= CALC_BIT_IN_WORD(x1
);
407 int mask
, mask_l
, mask_r
, i
;
408 /* If the addresses are equal, we only need to write one word
409 * which is an island. */
410 if (addr0
== addr1
) {
411 mask
= COMPUTE_HLINE_ISLAND_MASK(addr0_bit
, addr1_bit
);
412 WRITE_WORD_MODE(buff
, addr0
, mask
, mode
);
414 /* Otherwise we need to write the edges and then the middle. */
415 mask_l
= COMPUTE_HLINE_EDGE_L_MASK(addr0_bit
);
416 mask_r
= COMPUTE_HLINE_EDGE_R_MASK(addr1_bit
);
417 WRITE_WORD_MODE(buff
, addr0
, mask_l
, mode
);
418 WRITE_WORD_MODE(buff
, addr1
, mask_r
, mode
);
419 // Now write 0xffff words from start+1 to end-1.
420 for (i
= addr0
+ 1; i
<= addr1
- 1; i
++) {
422 WRITE_WORD_MODE(buff
, i
, m
, mode
);
428 * write_hline_lm: write both level and mask buffers.
430 * @param x0 x0 coordinate
431 * @param x1 x1 coordinate
432 * @param y y coordinate
433 * @param lmode 0 = clear, 1 = set, 2 = toggle
434 * @param mmode 0 = clear, 1 = set, 2 = toggle
436 void write_hline_lm(unsigned int x0
, unsigned int x1
, unsigned int y
, int lmode
, int mmode
)
438 // TODO: an optimisation would compute the masks and apply to
439 // both buffers simultaneously.
440 write_hline(draw_buffer_level
, x0
, x1
, y
, lmode
);
441 write_hline(draw_buffer_mask
, x0
, x1
, y
, mmode
);
445 * write_hline_outlined: outlined horizontal line with varying endcaps
446 * Always uses draw buffer.
448 * @param x0 x0 coordinate
449 * @param x1 x1 coordinate
450 * @param y y coordinate
451 * @param endcap0 0 = none, 1 = single pixel, 2 = full cap
452 * @param endcap1 0 = none, 1 = single pixel, 2 = full cap
453 * @param mode 0 = black outline, white body, 1 = white outline, black body
454 * @param mmode 0 = clear, 1 = set, 2 = toggle
456 void write_hline_outlined(unsigned int x0
, unsigned int x1
, unsigned int y
, int endcap0
, int endcap1
, int mode
, int mmode
)
460 SETUP_STROKE_FILL(stroke
, fill
, mode
)
464 // Draw the main body of the line.
465 write_hline_lm(x0
+ 1, x1
- 1, y
- 1, stroke
, mmode
);
466 write_hline_lm(x0
+ 1, x1
- 1, y
+ 1, stroke
, mmode
);
467 write_hline_lm(x0
+ 1, x1
- 1, y
, fill
, mmode
);
468 // Draw the endcaps, if any.
469 DRAW_ENDCAP_HLINE(endcap0
, x0
, y
, stroke
, fill
, mmode
);
470 DRAW_ENDCAP_HLINE(endcap1
, x1
, y
, stroke
, fill
, mmode
);
474 * write_vline: optimised vertical line writing algorithm
476 * @param buff pointer to buffer to write in
477 * @param x x coordinate
478 * @param y0 y0 coordinate
479 * @param y1 y1 coordinate
480 * @param mode 0 = clear, 1 = set, 2 = toggle
482 void write_vline(uint8_t *buff
, unsigned int x
, unsigned int y0
, unsigned int y1
, int mode
)
494 /* This is an optimised algorithm for writing vertical lines.
495 * We begin by finding the addresses of the x,y0 and x,y1 points. */
496 unsigned int addr0
= CALC_BUFF_ADDR(x
, y0
);
497 unsigned int addr1
= CALC_BUFF_ADDR(x
, y1
);
498 /* Then we calculate the pixel data to be written. */
499 unsigned int bitnum
= CALC_BIT_IN_WORD(x
);
500 uint16_t mask
= 1 << (7 - bitnum
);
501 /* Run from addr0 to addr1 placing pixels. Increment by the number
502 * of words n each graphics line. */
503 for (a
= addr0
; a
<= addr1
; a
+= GRAPHICS_WIDTH_REAL
/ 8) {
504 WRITE_WORD_MODE(buff
, a
, mask
, mode
);
509 * write_vline_lm: write both level and mask buffers.
511 * @param x x coordinate
512 * @param y0 y0 coordinate
513 * @param y1 y1 coordinate
514 * @param lmode 0 = clear, 1 = set, 2 = toggle
515 * @param mmode 0 = clear, 1 = set, 2 = toggle
517 void write_vline_lm(unsigned int x
, unsigned int y0
, unsigned int y1
, int lmode
, int mmode
)
519 // TODO: an optimisation would compute the masks and apply to
520 // both buffers simultaneously.
521 write_vline(draw_buffer_level
, x
, y0
, y1
, lmode
);
522 write_vline(draw_buffer_mask
, x
, y0
, y1
, mmode
);
526 * write_vline_outlined: outlined vertical line with varying endcaps
527 * Always uses draw buffer.
529 * @param x x coordinate
530 * @param y0 y0 coordinate
531 * @param y1 y1 coordinate
532 * @param endcap0 0 = none, 1 = single pixel, 2 = full cap
533 * @param endcap1 0 = none, 1 = single pixel, 2 = full cap
534 * @param mode 0 = black outline, white body, 1 = white outline, black body
535 * @param mmode 0 = clear, 1 = set, 2 = toggle
537 void write_vline_outlined(unsigned int x
, unsigned int y0
, unsigned int y1
, int endcap0
, int endcap1
, int mode
, int mmode
)
544 SETUP_STROKE_FILL(stroke
, fill
, mode
);
545 // Draw the main body of the line.
546 write_vline_lm(x
- 1, y0
+ 1, y1
- 1, stroke
, mmode
);
547 write_vline_lm(x
+ 1, y0
+ 1, y1
- 1, stroke
, mmode
);
548 write_vline_lm(x
, y0
+ 1, y1
- 1, fill
, mmode
);
549 // Draw the endcaps, if any.
550 DRAW_ENDCAP_VLINE(endcap0
, x
, y0
, stroke
, fill
, mmode
);
551 DRAW_ENDCAP_VLINE(endcap1
, x
, y1
, stroke
, fill
, mmode
);
555 * write_filled_rectangle: draw a filled rectangle.
557 * Uses an optimised algorithm which is similar to the horizontal
558 * line writing algorithm, but optimised for writing the lines
559 * multiple times without recalculating lots of stuff.
561 * @param buff pointer to buffer to write in
562 * @param x x coordinate (left)
563 * @param y y coordinate (top)
564 * @param width rectangle width
565 * @param height rectangle height
566 * @param mode 0 = clear, 1 = set, 2 = toggle
568 void write_filled_rectangle(uint8_t *buff
, unsigned int x
, unsigned int y
, unsigned int width
, unsigned int height
, int mode
)
570 unsigned int yy
, addr0_old
, addr1_old
;
573 CHECK_COORD_X(x
+ width
);
574 CHECK_COORD_Y(y
+ height
);
575 if (width
<= 0 || height
<= 0) {
578 // Calculate as if the rectangle was only a horizontal line. We then
579 // step these addresses through each row until we iterate `height` times.
580 unsigned int addr0
= CALC_BUFF_ADDR(x
, y
);
581 unsigned int addr1
= CALC_BUFF_ADDR(x
+ width
, y
);
582 unsigned int addr0_bit
= CALC_BIT_IN_WORD(x
);
583 unsigned int addr1_bit
= CALC_BIT_IN_WORD(x
+ width
);
584 unsigned int mask
, mask_l
, mask_r
, i
;
585 // If the addresses are equal, we need to write one word vertically.
586 if (addr0
== addr1
) {
587 mask
= COMPUTE_HLINE_ISLAND_MASK(addr0_bit
, addr1_bit
);
589 WRITE_WORD_MODE(buff
, addr0
, mask
, mode
);
590 addr0
+= GRAPHICS_WIDTH_REAL
/ 8;
593 // Otherwise we need to write the edges and then the middle repeatedly.
594 mask_l
= COMPUTE_HLINE_EDGE_L_MASK(addr0_bit
);
595 mask_r
= COMPUTE_HLINE_EDGE_R_MASK(addr1_bit
);
596 // Write edges first.
600 while (yy
< height
) {
601 WRITE_WORD_MODE(buff
, addr0
, mask_l
, mode
);
602 WRITE_WORD_MODE(buff
, addr1
, mask_r
, mode
);
603 addr0
+= GRAPHICS_WIDTH_REAL
/ 8;
604 addr1
+= GRAPHICS_WIDTH_REAL
/ 8;
607 // Now write 0xffff words from start+1 to end-1 for each row.
611 while (yy
< height
) {
612 for (i
= addr0
+ 1; i
<= addr1
- 1; i
++) {
614 WRITE_WORD_MODE(buff
, i
, m
, mode
);
616 addr0
+= GRAPHICS_WIDTH_REAL
/ 8;
617 addr1
+= GRAPHICS_WIDTH_REAL
/ 8;
624 * write_filled_rectangle_lm: draw a filled rectangle on both draw buffers.
626 * @param x x coordinate (left)
627 * @param y y coordinate (top)
628 * @param width rectangle width
629 * @param height rectangle height
630 * @param lmode 0 = clear, 1 = set, 2 = toggle
631 * @param mmode 0 = clear, 1 = set, 2 = toggle
633 void write_filled_rectangle_lm(unsigned int x
, unsigned int y
, unsigned int width
, unsigned int height
, int lmode
, int mmode
)
635 write_filled_rectangle(draw_buffer_mask
, x
, y
, width
, height
, mmode
);
636 write_filled_rectangle(draw_buffer_level
, x
, y
, width
, height
, lmode
);
640 * write_rectangle_outlined: draw an outline of a rectangle. Essentially
641 * a convenience wrapper for draw_hline_outlined and draw_vline_outlined.
643 * @param x x coordinate (left)
644 * @param y y coordinate (top)
645 * @param width rectangle width
646 * @param height rectangle height
647 * @param mode 0 = black outline, white body, 1 = white outline, black body
648 * @param mmode 0 = clear, 1 = set, 2 = toggle
650 void write_rectangle_outlined(unsigned int x
, unsigned int y
, int width
, int height
, int mode
, int mmode
)
652 // CHECK_COORDS(x, y);
653 // CHECK_COORDS(x + width, y + height);
654 // if((x + width) > DISP_WIDTH) width = DISP_WIDTH - x;
655 // if((y + height) > DISP_HEIGHT) height = DISP_HEIGHT - y;
656 write_hline_outlined(x
, x
+ width
, y
, ENDCAP_ROUND
, ENDCAP_ROUND
, mode
, mmode
);
657 write_hline_outlined(x
, x
+ width
, y
+ height
, ENDCAP_ROUND
, ENDCAP_ROUND
, mode
, mmode
);
658 write_vline_outlined(x
, y
, y
+ height
, ENDCAP_ROUND
, ENDCAP_ROUND
, mode
, mmode
);
659 write_vline_outlined(x
+ width
, y
, y
+ height
, ENDCAP_ROUND
, ENDCAP_ROUND
, mode
, mmode
);
663 * write_circle: draw the outline of a circle on a given buffer,
664 * with an optional dash pattern for the line instead of a normal line.
666 * @param buff pointer to buffer to write in
667 * @param cx origin x coordinate
668 * @param cy origin y coordinate
670 * @param dashp dash period (pixels) - zero for no dash
671 * @param mode 0 = clear, 1 = set, 2 = toggle
673 void write_circle(uint8_t *buff
, unsigned int cx
, unsigned int cy
, unsigned int r
, unsigned int dashp
, int mode
)
675 CHECK_COORDS(cx
, cy
);
676 int error
= -r
, x
= r
, y
= 0;
678 if (dashp
== 0 || (y
% dashp
) < (dashp
/ 2)) {
679 CIRCLE_PLOT_8(buff
, cx
, cy
, x
, y
, mode
);
681 error
+= (y
* 2) + 1;
691 * write_circle_outlined: draw an outlined circle on the draw buffer.
693 * @param cx origin x coordinate
694 * @param cy origin y coordinate
696 * @param dashp dash period (pixels) - zero for no dash
697 * @param bmode 0 = 4-neighbour border, 1 = 8-neighbour border
698 * @param mode 0 = black outline, white body, 1 = white outline, black body
699 * @param mmode 0 = clear, 1 = set, 2 = toggle
701 void write_circle_outlined(unsigned int cx
, unsigned int cy
, unsigned int r
, unsigned int dashp
, int bmode
, int mode
, int mmode
)
705 CHECK_COORDS(cx
, cy
);
706 SETUP_STROKE_FILL(stroke
, fill
, mode
);
707 // This is a two step procedure. First, we draw the outline of the
708 // circle, then we draw the inner part.
709 int error
= -r
, x
= r
, y
= 0;
711 if (dashp
== 0 || (y
% dashp
) < (dashp
/ 2)) {
712 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
+ 1, y
, mmode
);
713 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
+ 1, y
, stroke
);
714 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
, y
+ 1, mmode
);
715 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
, y
+ 1, stroke
);
716 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
- 1, y
, mmode
);
717 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
- 1, y
, stroke
);
718 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
, y
- 1, mmode
);
719 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
, y
- 1, stroke
);
721 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
+ 1, y
+ 1, mmode
);
722 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
+ 1, y
+ 1, stroke
);
723 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
- 1, y
- 1, mmode
);
724 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
- 1, y
- 1, stroke
);
727 error
+= (y
* 2) + 1;
738 if (dashp
== 0 || (y
% dashp
) < (dashp
/ 2)) {
739 CIRCLE_PLOT_8(draw_buffer_mask
, cx
, cy
, x
, y
, mmode
);
740 CIRCLE_PLOT_8(draw_buffer_level
, cx
, cy
, x
, y
, fill
);
742 error
+= (y
* 2) + 1;
752 * write_circle_filled: fill a circle on a given buffer.
754 * @param buff pointer to buffer to write in
755 * @param cx origin x coordinate
756 * @param cy origin y coordinate
758 * @param mode 0 = clear, 1 = set, 2 = toggle
760 void write_circle_filled(uint8_t *buff
, unsigned int cx
, unsigned int cy
, unsigned int r
, int mode
)
762 CHECK_COORDS(cx
, cy
);
763 int error
= -r
, x
= r
, y
= 0, xch
= 0;
764 // It turns out that filled circles can take advantage of the midpoint
765 // circle algorithm. We simply draw very fast horizontal lines across each
766 // pair of X,Y coordinates. In some cases, this can even be faster than
767 // drawing an outlined circle!
769 // Due to multiple writes to each set of pixels, we have a special exception
770 // for when using the toggling draw mode.
773 write_hline(buff
, cx
- x
, cx
+ x
, cy
+ y
, mode
);
774 write_hline(buff
, cx
- x
, cx
+ x
, cy
- y
, mode
);
775 if (mode
!= 2 || (mode
== 2 && xch
&& (cx
- x
) != (cx
- y
))) {
776 write_hline(buff
, cx
- y
, cx
+ y
, cy
+ x
, mode
);
777 write_hline(buff
, cx
- y
, cx
+ y
, cy
- x
, mode
);
781 error
+= (y
* 2) + 1;
789 // Handle toggle mode.
791 write_hline(buff
, cx
- r
, cx
+ r
, cy
, mode
);
796 * write_line: Draw a line of arbitrary angle.
798 * @param buff pointer to buffer to write in
799 * @param x0 first x coordinate
800 * @param y0 first y coordinate
801 * @param x1 second x coordinate
802 * @param y1 second y coordinate
803 * @param mode 0 = clear, 1 = set, 2 = toggle
805 void write_line(uint8_t *buff
, unsigned int x0
, unsigned int y0
, unsigned int x1
, unsigned int y1
, int mode
)
807 // Based on http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
808 unsigned int steep
= abs(y1
- y0
) > abs(x1
- x0
);
818 int deltax
= x1
- x0
;
819 unsigned int deltay
= abs(y1
- y0
);
820 int error
= deltax
/ 2;
823 unsigned int x
; // , lasty = y, stox = 0;
829 for (x
= x0
; x
< x1
; x
++) {
831 write_pixel(buff
, y
, x
, mode
);
833 write_pixel(buff
, x
, y
, mode
);
844 * write_line_lm: Draw a line of arbitrary angle.
846 * @param x0 first x coordinate
847 * @param y0 first y coordinate
848 * @param x1 second x coordinate
849 * @param y1 second y coordinate
850 * @param mmode 0 = clear, 1 = set, 2 = toggle
851 * @param lmode 0 = clear, 1 = set, 2 = toggle
853 void write_line_lm(unsigned int x0
, unsigned int y0
, unsigned int x1
, unsigned int y1
, int mmode
, int lmode
)
855 write_line(draw_buffer_mask
, x0
, y0
, x1
, y1
, mmode
);
856 write_line(draw_buffer_level
, x0
, y0
, x1
, y1
, lmode
);
860 * write_line_outlined: Draw a line of arbitrary angle, with an outline.
862 * @param buff pointer to buffer to write in
863 * @param x0 first x coordinate
864 * @param y0 first y coordinate
865 * @param x1 second x coordinate
866 * @param y1 second y coordinate
867 * @param endcap0 0 = none, 1 = single pixel, 2 = full cap
868 * @param endcap1 0 = none, 1 = single pixel, 2 = full cap
869 * @param mode 0 = black outline, white body, 1 = white outline, black body
870 * @param mmode 0 = clear, 1 = set, 2 = toggle
872 void write_line_outlined(unsigned int x0
, unsigned int y0
, unsigned int x1
, unsigned int y1
,
873 __attribute__((unused
)) int endcap0
, __attribute__((unused
)) int endcap1
,
876 // Based on http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
877 // This could be improved for speed.
887 int steep
= abs(y1
- y0
) > abs(x1
- x0
);
896 int deltax
= x1
- x0
;
897 unsigned int deltay
= abs(y1
- y0
);
898 int error
= deltax
/ 2;
908 for (x
= x0
; x
< x1
; x
++) {
910 write_pixel_lm(y
- 1, x
, mmode
, omode
);
911 write_pixel_lm(y
+ 1, x
, mmode
, omode
);
912 write_pixel_lm(y
, x
- 1, mmode
, omode
);
913 write_pixel_lm(y
, x
+ 1, mmode
, omode
);
915 write_pixel_lm(x
- 1, y
, mmode
, omode
);
916 write_pixel_lm(x
+ 1, y
, mmode
, omode
);
917 write_pixel_lm(x
, y
- 1, mmode
, omode
);
918 write_pixel_lm(x
, y
+ 1, mmode
, omode
);
926 // Now draw the innards.
929 for (x
= x0
; x
< x1
; x
++) {
931 write_pixel_lm(y
, x
, mmode
, imode
);
933 write_pixel_lm(x
, y
, mmode
, imode
);
944 * write_word_misaligned: Write a misaligned word across two addresses
947 * This allows for many pixels to be set in one write.
949 * @param buff buffer to write in
950 * @param word word to write (16 bits)
951 * @param addr address of first word
952 * @param xoff x offset (0-15)
953 * @param mode 0 = clear, 1 = set, 2 = toggle
955 void write_word_misaligned(uint8_t *buff
, uint16_t word
, unsigned int addr
, unsigned int xoff
, int mode
)
957 int16_t firstmask
= word
>> xoff
;
958 int16_t lastmask
= word
<< (16 - xoff
);
960 WRITE_WORD_MODE(buff
, addr
+ 1, firstmask
&& 0x00ff, mode
);
961 WRITE_WORD_MODE(buff
, addr
, (firstmask
& 0xff00) >> 8, mode
);
963 WRITE_WORD_MODE(buff
, addr
+ 2, (lastmask
& 0xff00) >> 8, mode
);
968 * write_word_misaligned_NAND: Write a misaligned word across two addresses
969 * with an x offset, using a NAND mask.
971 * This allows for many pixels to be set in one write.
973 * @param buff buffer to write in
974 * @param word word to write (16 bits)
975 * @param addr address of first word
976 * @param xoff x offset (0-15)
978 * This is identical to calling write_word_misaligned with a mode of 0 but
979 * it doesn't go through a lot of switch logic which slows down text writing
982 void write_word_misaligned_NAND(uint8_t *buff
, uint16_t word
, unsigned int addr
, unsigned int xoff
)
984 uint16_t firstmask
= word
>> xoff
;
985 uint16_t lastmask
= word
<< (16 - xoff
);
987 WRITE_WORD_NAND(buff
, addr
+ 1, firstmask
& 0x00ff);
988 WRITE_WORD_NAND(buff
, addr
, (firstmask
& 0xff00) >> 8);
990 WRITE_WORD_NAND(buff
, addr
+ 2, (lastmask
& 0xff00) >> 8);
995 * write_word_misaligned_OR: Write a misaligned word across two addresses
996 * with an x offset, using an OR mask.
998 * This allows for many pixels to be set in one write.
1000 * @param buff buffer to write in
1001 * @param word word to write (16 bits)
1002 * @param addr address of first word
1003 * @param xoff x offset (0-15)
1005 * This is identical to calling write_word_misaligned with a mode of 1 but
1006 * it doesn't go through a lot of switch logic which slows down text writing
1009 void write_word_misaligned_OR(uint8_t *buff
, uint16_t word
, unsigned int addr
, unsigned int xoff
)
1011 uint16_t firstmask
= word
>> xoff
;
1012 uint16_t lastmask
= word
<< (16 - xoff
);
1014 WRITE_WORD_OR(buff
, addr
+ 1, firstmask
& 0x00ff);
1015 WRITE_WORD_OR(buff
, addr
, (firstmask
& 0xff00) >> 8);
1017 WRITE_WORD_OR(buff
, addr
+ 2, (lastmask
& 0xff00) >> 8);
1022 * write_word_misaligned_lm: Write a misaligned word across two
1023 * words, in both level and mask buffers. This is core to the text
1026 * @param buff buffer to write in
1027 * @param word word to write (16 bits)
1028 * @param addr address of first word
1029 * @param xoff x offset (0-15)
1030 * @param lmode 0 = clear, 1 = set, 2 = toggle
1031 * @param mmode 0 = clear, 1 = set, 2 = toggle
1033 void write_word_misaligned_lm(uint16_t wordl
, uint16_t wordm
, unsigned int addr
, unsigned int xoff
, int lmode
, int mmode
)
1035 write_word_misaligned(draw_buffer_level
, wordl
, addr
, xoff
, lmode
);
1036 write_word_misaligned(draw_buffer_mask
, wordm
, addr
, xoff
, mmode
);
1040 * fetch_font_info: Fetch font info structs.
1042 * @param ch character
1043 * @param font font id
1045 int fetch_font_info(uint8_t ch
, int font
, struct FontEntry
*font_info
, char *lookup
)
1047 // First locate the font struct.
1048 if ((unsigned int)font
> SIZEOF_ARRAY(fonts
)) {
1049 return 0; // font does not exist, exit.
1051 // Load the font info; IDs are always sequential.
1052 *font_info
= fonts
[font
];
1053 // Locate character in font lookup table. (If required.)
1054 if (lookup
!= NULL
) {
1055 *lookup
= font_info
->lookup
[ch
];
1056 if (*lookup
== 0xff) {
1057 return 0; // character doesn't exist, don't bother writing it.
1064 * write_char16: Draw a character on the current draw buffer.
1065 * Currently supports outlined characters and characters with
1066 * a width of up to 8 pixels.
1068 * @param ch character to write
1069 * @param x x coordinate (left)
1070 * @param y y coordinate (top)
1071 * @param flags flags to write with (see gfx.h)
1072 * @param font font to use
1074 void write_char16(char ch
, unsigned int x
, unsigned int y
, int font
)
1076 unsigned int yy
, addr_temp
, row
, row_temp
, xshift
;
1077 uint16_t and_mask
, or_mask
, levels
;
1078 struct FontEntry font_info
;
1081 fetch_font_info(0, font
, &font_info
, NULL
);
1083 // Compute starting address (for x,y) of character.
1084 int addr
= CALC_BUFF_ADDR(x
, y
);
1085 int wbit
= CALC_BIT_IN_WORD(x
);
1086 // If font only supports lowercase or uppercase, make the letter
1087 // lowercase or uppercase.
1088 // How big is the character? We handle characters up to 8 pixels
1089 // wide for now. Support for large characters may be added in future.
1091 // Ensure we don't overflow.
1092 if (x
+ wbit
> GRAPHICS_WIDTH_REAL
) {
1095 // Load data pointer.
1096 row
= ch
* font_info
.height
;
1099 xshift
= 16 - font_info
.width
;
1100 // We can write mask words easily.
1101 for (yy
= y
; yy
< y
+ font_info
.height
; yy
++) {
1103 write_word_misaligned_OR(draw_buffer_mask
, font_mask12x18
[row
] << xshift
, addr
, wbit
);
1105 write_word_misaligned_OR(draw_buffer_mask
, font_mask8x10
[row
] << xshift
, addr
, wbit
);
1107 addr
+= GRAPHICS_WIDTH_REAL
/ 8;
1110 // Level bits are more complicated. We need to set or clear
1111 // level bits, but only where the mask bit is set; otherwise,
1112 // we need to leave them alone. To do this, for each word, we
1113 // construct an AND mask and an OR mask, and apply each individually.
1116 for (yy
= y
; yy
< y
+ font_info
.height
; yy
++) {
1118 levels
= font_frame12x18
[row
];
1119 // if(!(flags & FONT_INVERT)) // data is normally inverted
1121 or_mask
= font_mask12x18
[row
] << xshift
;
1122 and_mask
= (font_mask12x18
[row
] & levels
) << xshift
;
1124 levels
= font_frame8x10
[row
];
1125 // if(!(flags & FONT_INVERT)) // data is normally inverted
1127 or_mask
= font_mask8x10
[row
] << xshift
;
1128 and_mask
= (font_mask8x10
[row
] & levels
) << xshift
;
1130 write_word_misaligned_OR(draw_buffer_level
, or_mask
, addr
, wbit
);
1131 // If we're not bold write the AND mask.
1132 // if(!(flags & FONT_BOLD))
1133 write_word_misaligned_NAND(draw_buffer_level
, and_mask
, addr
, wbit
);
1134 addr
+= GRAPHICS_WIDTH_REAL
/ 8;
1141 * write_char: Draw a character on the current draw buffer.
1142 * Currently supports outlined characters and characters with
1143 * a width of up to 8 pixels.
1145 * @param ch character to write
1146 * @param x x coordinate (left)
1147 * @param y y coordinate (top)
1148 * @param flags flags to write with (see gfx.h)
1149 * @param font font to use
1151 void write_char(char ch
, unsigned int x
, unsigned int y
, int flags
, int font
)
1153 unsigned int yy
, addr_temp
, row
, row_temp
, xshift
;
1154 uint16_t and_mask
, or_mask
, levels
;
1155 struct FontEntry font_info
;
1158 fetch_font_info(ch
, font
, &font_info
, &lookup
);
1159 // Compute starting address (for x,y) of character.
1160 unsigned int addr
= CALC_BUFF_ADDR(x
, y
);
1161 unsigned int wbit
= CALC_BIT_IN_WORD(x
);
1162 // If font only supports lowercase or uppercase, make the letter
1163 // lowercase or uppercase.
1164 /*if(font_info.flags & FONT_LOWERCASE_ONLY)
1166 if(font_info.flags & FONT_UPPERCASE_ONLY)
1168 fetch_font_info(ch
, font
, &font_info
, &lookup
);
1169 // How big is the character? We handle characters up to 8 pixels
1170 // wide for now. Support for large characters may be added in future.
1171 if (font_info
.width
<= 8) {
1172 // Ensure we don't overflow.
1173 if (x
+ wbit
> GRAPHICS_WIDTH_REAL
) {
1176 // Load data pointer.
1177 row
= lookup
* font_info
.height
* 2;
1180 xshift
= 16 - font_info
.width
;
1181 // We can write mask words easily.
1182 for (yy
= y
; yy
< y
+ font_info
.height
; yy
++) {
1183 write_word_misaligned_OR(draw_buffer_mask
, font_info
.data
[row
] << xshift
, addr
, wbit
);
1184 addr
+= GRAPHICS_WIDTH_REAL
/ 8;
1187 // Level bits are more complicated. We need to set or clear
1188 // level bits, but only where the mask bit is set; otherwise,
1189 // we need to leave them alone. To do this, for each word, we
1190 // construct an AND mask and an OR mask, and apply each individually.
1193 for (yy
= y
; yy
< y
+ font_info
.height
; yy
++) {
1194 levels
= font_info
.data
[row
+ font_info
.height
];
1195 if (!(flags
& FONT_INVERT
)) {
1196 // data is normally inverted
1199 or_mask
= font_info
.data
[row
] << xshift
;
1200 and_mask
= (font_info
.data
[row
] & levels
) << xshift
;
1201 write_word_misaligned_OR(draw_buffer_level
, or_mask
, addr
, wbit
);
1202 // If we're not bold write the AND mask.
1203 // if(!(flags & FONT_BOLD))
1204 write_word_misaligned_NAND(draw_buffer_level
, and_mask
, addr
, wbit
);
1205 addr
+= GRAPHICS_WIDTH_REAL
/ 8;
1212 * calc_text_dimensions: Calculate the dimensions of a
1213 * string in a given font. Supports new lines and
1214 * carriage returns in text.
1216 * @param str string to calculate dimensions of
1217 * @param font_info font info structure
1218 * @param xs horizontal spacing
1219 * @param ys vertical spacing
1220 * @param dim return result: struct FontDimensions
1222 void calc_text_dimensions(char *str
, struct FontEntry font
, int xs
, int ys
, struct FontDimensions
*dim
)
1224 int max_length
= 0, line_length
= 0, lines
= 1;
1228 if (*str
== '\n' || *str
== '\r') {
1229 if (line_length
> max_length
) {
1230 max_length
= line_length
;
1237 if (line_length
> max_length
) {
1238 max_length
= line_length
;
1240 dim
->width
= max_length
* (font
.width
+ xs
);
1241 dim
->height
= lines
* (font
.height
+ ys
);
1245 * write_string: Draw a string on the screen with certain
1246 * alignment parameters.
1248 * @param str string to write
1249 * @param x x coordinate
1250 * @param y y coordinate
1251 * @param xs horizontal spacing
1252 * @param ys horizontal spacing
1253 * @param va vertical align
1254 * @param ha horizontal align
1255 * @param flags flags (passed to write_char)
1258 void write_string(char *str
, unsigned int x
, unsigned int y
, unsigned int xs
, unsigned int ys
, int va
, int ha
, int flags
, int font
)
1260 int xx
= 0, yy
= 0, xx_original
= 0;
1261 struct FontEntry font_info
;
1262 struct FontDimensions dim
;
1264 // Determine font info and dimensions/position of the string.
1265 fetch_font_info(0, font
, &font_info
, NULL
);
1266 calc_text_dimensions(str
, font_info
, xs
, ys
, &dim
);
1271 case TEXT_VA_MIDDLE
:
1272 yy
= y
- (dim
.height
/ 2);
1274 case TEXT_VA_BOTTOM
:
1275 yy
= y
- dim
.height
;
1282 case TEXT_HA_CENTER
:
1283 xx
= x
- (dim
.width
/ 2);
1289 // Then write each character.
1292 if (*str
== '\n' || *str
== '\r') {
1293 yy
+= ys
+ font_info
.height
;
1296 if (xx
>= 0 && xx
< GRAPHICS_WIDTH_REAL
) {
1297 if (font_info
.id
< 2) {
1298 write_char(*str
, xx
, yy
, flags
, font
);
1300 write_char16(*str
, xx
, yy
, font
);
1303 xx
+= font_info
.width
+ xs
;
1310 * write_string_formatted: Draw a string with format escape
1311 * sequences in it. Allows for complex text effects.
1313 * @param str string to write (with format data)
1314 * @param x x coordinate
1315 * @param y y coordinate
1316 * @param xs default horizontal spacing
1317 * @param ys default horizontal spacing
1318 * @param va vertical align
1319 * @param ha horizontal align
1320 * @param flags flags (passed to write_char)
1322 void write_string_formatted(char *str
, unsigned int x
, unsigned int y
, unsigned int xs
, unsigned int ys
,
1323 __attribute__((unused
)) int va
, __attribute__((unused
)) int ha
, int flags
)
1325 int fcode
= 0, fptr
= 0, font
= 0, fwidth
= 0, fheight
= 0, xx
= x
, yy
= y
, max_xx
= 0, max_height
= 0;
1326 struct FontEntry font_info
;
1328 // Retrieve sizes of the fonts: bigfont and smallfont.
1329 fetch_font_info(0, 0, &font_info
, NULL
);
1330 int smallfontwidth
= font_info
.width
, smallfontheight
= font_info
.height
;
1331 fetch_font_info(0, 1, &font_info
, NULL
);
1332 int bigfontwidth
= font_info
.width
, bigfontheight
= font_info
.height
;
1333 // 11 byte stack with last byte as NUL.
1336 // First, we need to parse the string for format characters and
1337 // work out a bounding box. We'll parse again for the final output.
1338 // This is a simple state machine parser.
1341 if (*str
== '<' && fcode
== 1) {
1342 // escape code: skip
1345 if (*str
== '<' && fcode
== 0) {
1346 // begin format code?
1350 if (*str
== '>' && fcode
== 1) {
1352 if (strcmp(fstack
, "B")) {
1353 // switch to "big" font (font #1)
1354 fwidth
= bigfontwidth
;
1355 fheight
= bigfontheight
;
1356 } else if (strcmp(fstack
, "S")) {
1357 // switch to "small" font (font #0)
1358 fwidth
= smallfontwidth
;
1359 fheight
= smallfontheight
;
1361 if (fheight
> max_height
) {
1362 max_height
= fheight
;
1364 // Skip over this byte. Go to next byte.
1368 if (*str
!= '<' && *str
!= '>' && fcode
== 1) {
1369 // Add to the format stack (up to 10 bytes.)
1371 // stop adding bytes
1372 str
++; // go to next byte
1375 fstack
[fptr
++] = *str
;
1376 fstack
[fptr
] = '\0'; // clear next byte (ready for next char or to terminate string.)
1379 // Not a format code, raw text.
1391 // Reset string pointer.
1393 // Now we've parsed it and got a bbox, we need to work out the dimensions of it
1394 // and how to align it.
1395 /*int width = max_xx - x;
1396 int height = yy - y;
1400 case TEXT_VA_TOP: ay = yy; break;
1401 case TEXT_VA_MIDDLE: ay = yy - (height / 2); break;
1402 case TEXT_VA_BOTTOM: ay = yy - height; break;
1406 case TEXT_HA_LEFT: ax = x; break;
1407 case TEXT_HA_CENTER: ax = x - (width / 2); break;
1408 case TEXT_HA_RIGHT: ax = x - width; break;
1410 // So ax,ay is our new text origin. Parse the text format again and paint
1411 // the text on the display.
1418 if (*str
== '<' && fcode
== 1) {
1419 // escape code: skip
1422 if (*str
== '<' && fcode
== 0) {
1423 // begin format code?
1427 if (*str
== '>' && fcode
== 1) {
1429 if (strcmp(fstack
, "B")) {
1430 // switch to "big" font (font #1)
1431 fwidth
= bigfontwidth
;
1432 fheight
= bigfontheight
;
1434 } else if (strcmp(fstack
, "S")) {
1435 // switch to "small" font (font #0)
1436 fwidth
= smallfontwidth
;
1437 fheight
= smallfontheight
;
1440 // Skip over this byte. Go to next byte.
1444 if (*str
!= '<' && *str
!= '>' && fcode
== 1) {
1445 // Add to the format stack (up to 10 bytes.)
1447 // stop adding bytes
1448 str
++; // go to next byte
1451 fstack
[fptr
++] = *str
;
1452 fstack
[fptr
] = '\0'; // clear next byte (ready for next char or to terminate string.)
1455 // Not a format code, raw text. So we draw it.
1456 // TODO - different font sizes.
1457 write_char(*str
, xx
, yy
+ (max_height
- fheight
), flags
, font
);
1475 void drawAttitude(uint16_t x
, uint16_t y
, int16_t pitch
, int16_t roll
, uint16_t size
)
1477 int16_t a
= mySin(roll
+ 360);
1478 int16_t b
= myCos(roll
+ 360);
1479 int16_t c
= mySin(roll
+ 90 + 360) * 5 / 100;
1480 int16_t d
= myCos(roll
+ 90 + 360) * 5 / 100;
1485 int16_t indi30x1
= myCos(30) * (size
/ 2 + 1) / 100;
1486 int16_t indi30y1
= mySin(30) * (size
/ 2 + 1) / 100;
1488 int16_t indi30x2
= myCos(30) * (size
/ 2 + 4) / 100;
1489 int16_t indi30y2
= mySin(30) * (size
/ 2 + 4) / 100;
1491 int16_t indi60x1
= myCos(60) * (size
/ 2 + 1) / 100;
1492 int16_t indi60y1
= mySin(60) * (size
/ 2 + 1) / 100;
1494 int16_t indi60x2
= myCos(60) * (size
/ 2 + 4) / 100;
1495 int16_t indi60y2
= mySin(60) * (size
/ 2 + 4) / 100;
1504 a
= (a
* (size
/ 2)) / 100;
1505 b
= (b
* (size
/ 2)) / 100;
1507 if (roll
< -90 || roll
> 90) {
1515 // drawLine((x)-1-(size/2+4), (y)-1, (x)-1 - (size/2+1), (y)-1);
1516 // drawLine((x)-1+(size/2+4), (y)-1, (x)-1 + (size/2+1), (y)-1);
1517 write_line_outlined((x
) - 1 - (size
/ 2 + 4), (y
) - 1, (x
) - 1 - (size
/ 2 + 1), (y
) - 1, 0, 0, 0, 1);
1518 write_line_outlined((x
) - 1 + (size
/ 2 + 4), (y
) - 1, (x
) - 1 + (size
/ 2 + 1), (y
) - 1, 0, 0, 0, 1);
1521 // drawLine((x)-1+indi30x1, (y)-1-indi30y1, (x)-1 + indi30x2, (y)-1 - indi30y2);
1522 // drawLine((x)-1-indi30x1, (y)-1-indi30y1, (x)-1 - indi30x2, (y)-1 - indi30y2);
1523 write_line_outlined((x
) - 1 + indi30x1
, (y
) - 1 - indi30y1
, (x
) - 1 + indi30x2
, (y
) - 1 - indi30y2
, 0, 0, 0, 1);
1524 write_line_outlined((x
) - 1 - indi30x1
, (y
) - 1 - indi30y1
, (x
) - 1 - indi30x2
, (y
) - 1 - indi30y2
, 0, 0, 0, 1);
1526 // drawLine((x)-1+indi60x1, (y)-1-indi60y1, (x)-1 + indi60x2, (y)-1 - indi60y2);
1527 // drawLine((x)-1-indi60x1, (y)-1-indi60y1, (x)-1 - indi60x2, (y)-1 - indi60y2);
1528 write_line_outlined((x
) - 1 + indi60x1
, (y
) - 1 - indi60y1
, (x
) - 1 + indi60x2
, (y
) - 1 - indi60y2
, 0, 0, 0, 1);
1529 write_line_outlined((x
) - 1 - indi60x1
, (y
) - 1 - indi60y1
, (x
) - 1 - indi60x2
, (y
) - 1 - indi60y2
, 0, 0, 0, 1);
1531 // drawLine((x)-1, (y)-1-(size/2+4), (x)-1, (y)-1 - (size/2+1));
1532 write_line_outlined((x
) - 1, (y
) - 1 - (size
/ 2 + 4), (x
) - 1, (y
) - 1 - (size
/ 2 + 1), 0, 0, 0, 1);
1535 // drawLine((x)-1 - b, (y)-1 + a, (x)-1 + b, (y)-1 - a); //Direction line
1536 write_line_outlined((x
) - 1 - b
, (y
) - 1 + a
, (x
) - 1 + b
, (y
) - 1 - a
, 0, 0, 0, 1); // Direction line
1538 // drawLine((x)-1 - b, (y)-1 + a, (x)-1 - b + d, (y)-1 + a - c);
1539 // drawLine((x)-1 + b + d, (y)-1 - a - c, (x)-1 + b, (y)-1 - a);
1540 write_line_outlined((x
) - 1 - b
, (y
) - 1 + a
, (x
) - 1 - b
+ d
, (y
) - 1 + a
- c
, 0, 0, 0, 1);
1541 write_line_outlined((x
) - 1 + b
+ d
, (y
) - 1 - a
- c
, (x
) - 1 + b
, (y
) - 1 - a
, 0, 0, 0, 1);
1544 // drawLine((x)-1, (y)-1, (x)-1 - k, (y)-1 - l);
1545 write_line_outlined((x
) - 1, (y
) - 1, (x
) - 1 - k
, (y
) - 1 - l
, 0, 0, 0, 1);
1547 // drawCircle(x-1, y-1, 5);
1548 // write_circle_outlined(x-1, y-1, 5,0,0,0,1);
1549 // drawCircle(x-1, y-1, size/2+4);
1550 // write_circle_outlined(x-1, y-1, size/2+4,0,0,0,1);
1553 void drawBattery(uint16_t x
, uint16_t y
, uint8_t battery
, uint16_t size
)
1559 /*drawLine((x)-1+(size/2-size/4), (y)-1, (x)-1 + (size/2+size/4), (y)-1);
1560 drawLine((x)-1+(size/2-size/4), (y)-1+1, (x)-1 + (size/2+size/4), (y)-1+1);
1562 drawLine((x)-1, (y)-1+2, (x)-1 + size, (y)-1+2);
1564 drawLine((x)-1, (y)-1+size*3, (x)-1 + size, (y)-1+size*3);
1566 drawLine((x)-1, (y)-1+2, (x)-1, (y)-1+size*3);
1569 drawLine((x)-1+size, (y)-1+2, (x)-1+size, (y)-1+size*3);*/
1571 write_rectangle_outlined((x
) - 1, (y
) - 1 + 2, size
, size
* 3, 0, 1);
1572 write_vline_lm((x
) - 1 + (size
/ 2 + size
/ 4) + 1, (y
) - 2, (y
) - 1 + 1, 0, 1);
1573 write_vline_lm((x
) - 1 + (size
/ 2 - size
/ 4) - 1, (y
) - 2, (y
) - 1 + 1, 0, 1);
1574 write_hline_lm((x
) - 1 + (size
/ 2 - size
/ 4), (x
) - 1 + (size
/ 2 + size
/ 4), (y
) - 2, 0, 1);
1575 write_hline_lm((x
) - 1 + (size
/ 2 - size
/ 4), (x
) - 1 + (size
/ 2 + size
/ 4), (y
) - 1, 1, 1);
1576 write_hline_lm((x
) - 1 + (size
/ 2 - size
/ 4), (x
) - 1 + (size
/ 2 + size
/ 4), (y
) - 1 + 1, 1, 1);
1578 batteryLines
= battery
* (size
* 3 - 2) / 100;
1579 for (i
= 0; i
< batteryLines
; i
++) {
1580 write_hline_lm((x
) - 1, (x
) - 1 + size
, (y
) - 1 + size
* 3 - i
, 1, 1);
1584 void printTime(uint16_t x
, uint16_t y
)
1589 sprintf(temp
, "%02d:%02d:%02d", timex
.hour
, timex
.min
, timex
.sec
);
1590 // printTextFB(x,y,temp);
1591 write_string(temp
, x
, y
, 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 3);
1595 void drawAltitude(uint16_t x, uint16_t y, int16_t alt, uint8_t dir) {
1599 uint16_t charx=x/16;
1604 sprintf(temp,"%c%6dm",updown,alt);
1605 printTextFB(charx,y+2,temp);
1607 drawBox(charx*16-3,y,charx*16+strlen(temp)*8+3,y+11);
1611 * hud_draw_vertical_scale: Draw a vertical scale.
1613 * @param v value to display as an integer
1614 * @param range range about value to display (+/- range/2 each direction)
1615 * @param halign horizontal alignment: -1 = left, +1 = right.
1616 * @param x x displacement (typ. 0)
1617 * @param y y displacement (typ. half display height)
1618 * @param height height of scale
1619 * @param mintick_step how often a minor tick is shown
1620 * @param majtick_step how often a major tick is shown
1621 * @param mintick_len minor tick length
1622 * @param majtick_len major tick length
1623 * @param boundtick_len boundary tick length
1624 * @param max_val maximum expected value (used to compute size of arrow ticker)
1625 * @param flags special flags (see hud.h.)
1627 void hud_draw_vertical_scale(int v
, int range
, int halign
, int x
, int y
, int height
, int mintick_step
, int majtick_step
, int mintick_len
, int majtick_len
,
1628 int boundtick_len
, __attribute__((unused
)) int max_val
, int flags
)
1630 char temp
[15]; // , temp2[15];
1631 struct FontEntry font_info
;
1632 struct FontDimensions dim
;
1633 // Halign should be in a small span.
1634 // MY_ASSERT(halign >= -1 && halign <= 1);
1635 // Compute the position of the elements.
1636 int majtick_start
= 0, majtick_end
= 0, mintick_start
= 0, mintick_end
= 0, boundtick_start
= 0, boundtick_end
= 0;
1640 majtick_end
= x
+ majtick_len
;
1642 mintick_end
= x
+ mintick_len
;
1643 boundtick_start
= x
;
1644 boundtick_end
= x
+ boundtick_len
;
1645 } else if (halign
== +1) {
1646 x
= x
- GRAPHICS_HDEADBAND
;
1647 majtick_start
= GRAPHICS_WIDTH_REAL
- x
- 1;
1648 majtick_end
= GRAPHICS_WIDTH_REAL
- x
- majtick_len
- 1;
1649 mintick_start
= GRAPHICS_WIDTH_REAL
- x
- 1;
1650 mintick_end
= GRAPHICS_WIDTH_REAL
- x
- mintick_len
- 1;
1651 boundtick_start
= GRAPHICS_WIDTH_REAL
- x
- 1;
1652 boundtick_end
= GRAPHICS_WIDTH_REAL
- x
- boundtick_len
- 1;
1654 // Retrieve width of large font (font #0); from this calculate the x spacing.
1655 fetch_font_info(0, 0, &font_info
, NULL
);
1656 int arrow_len
= (font_info
.height
/ 2) + 1; // FIXME, font info being loaded correctly??
1657 int text_x_spacing
= arrow_len
;
1658 int max_text_y
= 0, text_length
= 0;
1659 int small_font_char_width
= font_info
.width
+ 1; // +1 for horizontal spacing = 1
1660 // For -(range / 2) to +(range / 2), draw the scale.
1661 int range_2
= range
/ 2; // , height_2 = height / 2;
1662 int r
= 0, rr
= 0, rv
= 0, ys
= 0, style
= 0; // calc_ys = 0,
1663 // Iterate through each step.
1664 for (r
= -range_2
; r
<= +range_2
; r
++) {
1666 rr
= r
+ range_2
- v
; // normalise range for modulo, subtract value to move ticker tape
1667 rv
= -rr
+ range_2
; // for number display
1668 if (flags
& HUD_VSCALE_FLAG_NO_NEGATIVE
) {
1669 rr
+= majtick_step
/ 2;
1671 if (rr
% majtick_step
== 0) {
1672 style
= 1; // major tick
1673 } else if (rr
% mintick_step
== 0) {
1674 style
= 2; // minor tick
1678 if (flags
& HUD_VSCALE_FLAG_NO_NEGATIVE
&& rv
< 0) {
1682 // Calculate y position.
1683 ys
= ((long int)(r
* height
) / (long int)range
) + y
;
1684 // sprintf(temp, "ys=%d", ys);
1685 // con_puts(temp, 0);
1686 // Depending on style, draw a minor or a major tick.
1688 write_hline_outlined(majtick_start
, majtick_end
, ys
, 2, 2, 0, 1);
1689 memset(temp
, ' ', 10);
1690 // my_itoa(rv, temp);
1691 sprintf(temp
, "%d", rv
);
1692 text_length
= (strlen(temp
) + 1) * small_font_char_width
; // add 1 for margin
1693 if (text_length
> max_text_y
) {
1694 max_text_y
= text_length
;
1697 write_string(temp
, majtick_end
+ text_x_spacing
, ys
, 1, 0, TEXT_VA_MIDDLE
, TEXT_HA_LEFT
, 0, 1);
1699 write_string(temp
, majtick_end
- text_x_spacing
+ 1, ys
, 1, 0, TEXT_VA_MIDDLE
, TEXT_HA_RIGHT
, 0, 1);
1701 } else if (style
== 2) {
1702 write_hline_outlined(mintick_start
, mintick_end
, ys
, 2, 2, 0, 1);
1706 // Generate the string for the value, as well as calculating its dimensions.
1707 memset(temp
, ' ', 10);
1708 // my_itoa(v, temp);
1709 sprintf(temp
, "%d", v
);
1710 // TODO: add auto-sizing.
1711 calc_text_dimensions(temp
, font_info
, 1, 0, &dim
);
1714 xx
= majtick_end
+ text_x_spacing
;
1716 xx
= majtick_end
- text_x_spacing
;
1718 // Draw an arrow from the number to the point.
1719 for (i
= 0; i
< arrow_len
; i
++) {
1721 write_pixel_lm(xx
- arrow_len
+ i
, y
- i
- 1, 1, 1);
1722 write_pixel_lm(xx
- arrow_len
+ i
, y
+ i
- 1, 1, 1);
1723 write_hline_lm(xx
+ dim
.width
- 1, xx
- arrow_len
+ i
+ 1, y
- i
- 1, 0, 1);
1724 write_hline_lm(xx
+ dim
.width
- 1, xx
- arrow_len
+ i
+ 1, y
+ i
- 1, 0, 1);
1726 write_pixel_lm(xx
+ arrow_len
- i
, y
- i
- 1, 1, 1);
1727 write_pixel_lm(xx
+ arrow_len
- i
, y
+ i
- 1, 1, 1);
1728 write_hline_lm(xx
- dim
.width
- 1, xx
+ arrow_len
- i
- 1, y
- i
- 1, 0, 1);
1729 write_hline_lm(xx
- dim
.width
- 1, xx
+ arrow_len
- i
- 1, y
+ i
- 1, 0, 1);
1732 // write_hline_lm(xx - dim.width - 1, xx + (arrow_len - i), y - i - 1, 1, 1);
1733 // write_hline_lm(xx - dim.width - 1, xx + (arrow_len - i), y + i - 1, 1, 1);
1736 write_hline_lm(xx
, xx
+ dim
.width
- 1, y
- arrow_len
, 1, 1);
1737 write_hline_lm(xx
, xx
+ dim
.width
- 1, y
+ arrow_len
- 2, 1, 1);
1738 write_vline_lm(xx
+ dim
.width
- 1, y
- arrow_len
, y
+ arrow_len
- 2, 1, 1);
1740 write_hline_lm(xx
, xx
- dim
.width
- 1, y
- arrow_len
, 1, 1);
1741 write_hline_lm(xx
, xx
- dim
.width
- 1, y
+ arrow_len
- 2, 1, 1);
1742 write_vline_lm(xx
- dim
.width
- 1, y
- arrow_len
, y
+ arrow_len
- 2, 1, 1);
1746 write_string(temp
, xx
, y
, 1, 0, TEXT_VA_MIDDLE
, TEXT_HA_LEFT
, 0, 0);
1748 write_string(temp
, xx
, y
, 1, 0, TEXT_VA_MIDDLE
, TEXT_HA_RIGHT
, 0, 0);
1750 // Then, add a slow cut off on the edges, so the text doesn't sharply
1751 // disappear. We simply clear the areas above and below the ticker, and we
1752 // use little markers on the edges.
1754 write_filled_rectangle_lm(majtick_end
+ text_x_spacing
, y
+ (height
/ 2) - (font_info
.height
/ 2), max_text_y
- boundtick_start
, font_info
.height
, 0,
1756 write_filled_rectangle_lm(majtick_end
+ text_x_spacing
, y
- (height
/ 2) - (font_info
.height
/ 2), max_text_y
- boundtick_start
, font_info
.height
, 0,
1759 write_filled_rectangle_lm(majtick_end
- text_x_spacing
- max_text_y
, y
+ (height
/ 2) - (font_info
.height
/ 2), max_text_y
, font_info
.height
, 0, 0);
1760 write_filled_rectangle_lm(majtick_end
- text_x_spacing
- max_text_y
, y
- (height
/ 2) - (font_info
.height
/ 2), max_text_y
, font_info
.height
, 0, 0);
1762 write_hline_outlined(boundtick_start
, boundtick_end
, y
+ (height
/ 2), 2, 2, 0, 1);
1763 write_hline_outlined(boundtick_start
, boundtick_end
, y
- (height
/ 2), 2, 2, 0, 1);
1767 * hud_draw_compass: Draw a compass.
1769 * @param v value for the compass
1770 * @param range range about value to display (+/- range/2 each direction)
1771 * @param width length in pixels
1772 * @param x x displacement (typ. half display width)
1773 * @param y y displacement (typ. bottom of display)
1774 * @param mintick_step how often a minor tick is shown
1775 * @param majtick_step how often a major tick (heading "xx") is shown
1776 * @param mintick_len minor tick length
1777 * @param majtick_len major tick length
1778 * @param flags special flags (see hud.h.)
1780 void hud_draw_linear_compass(int v
, int range
, int width
, int x
, int y
, int mintick_step
, int majtick_step
, int mintick_len
, int majtick_len
, __attribute__((unused
)) int flags
)
1782 v
%= 360; // wrap, just in case.
1783 struct FontEntry font_info
;
1784 int majtick_start
= 0, majtick_end
= 0, mintick_start
= 0, mintick_end
= 0, textoffset
= 0;
1787 majtick_end
= y
- majtick_len
;
1789 mintick_end
= y
- mintick_len
;
1791 int r
, style
, rr
, xs
; // rv,
1792 int range_2
= range
/ 2;
1793 for (r
= -range_2
; r
<= +range_2
; r
++) {
1795 rr
= (v
+ r
+ 360) % 360; // normalise range for modulo, add to move compass track
1796 // rv = -rr + range_2; // for number display
1797 if (rr
% majtick_step
== 0) {
1798 style
= 1; // major tick
1799 } else if (rr
% mintick_step
== 0) {
1800 style
= 2; // minor tick
1803 // Calculate x position.
1804 xs
= ((long int)(r
* width
) / (long int)range
) + x
;
1807 write_vline_outlined(xs
, majtick_start
, majtick_end
, 2, 2, 0, 1);
1808 // Draw heading above this tick.
1809 // If it's not one of north, south, east, west, draw the heading.
1810 // Otherwise, draw one of the identifiers.
1812 // We abbreviate heading to two digits. This has the side effect of being easy to compute.
1813 headingstr
[0] = '0' + (rr
/ 100);
1814 headingstr
[1] = '0' + ((rr
/ 10) % 10);
1816 headingstr
[3] = 0; // nul to terminate
1820 headingstr
[0] = 'N';
1823 headingstr
[0] = 'E';
1826 headingstr
[0] = 'S';
1829 headingstr
[0] = 'W';
1837 write_string(headingstr
, xs
+ 1, majtick_start
+ textoffset
, 1, 0, TEXT_VA_MIDDLE
, TEXT_HA_CENTER
, 0, 1);
1838 } else if (style
== 2) {
1839 write_vline_outlined(xs
, mintick_start
, mintick_end
, 2, 2, 0, 1);
1843 // Then, draw a rectangle with the present heading in it.
1844 // We want to cover up any other markers on the bottom.
1845 // First compute font size.
1846 fetch_font_info(0, 3, &font_info
, NULL
);
1847 int text_width
= (font_info
.width
+ 1) * 3;
1848 int rect_width
= text_width
+ 2;
1849 write_filled_rectangle_lm(x
- (rect_width
/ 2), majtick_start
+ 2, rect_width
, font_info
.height
+ 2, 0, 1);
1850 write_rectangle_outlined(x
- (rect_width
/ 2), majtick_start
+ 2, rect_width
, font_info
.height
+ 2, 0, 1);
1851 headingstr
[0] = '0' + (v
/ 100);
1852 headingstr
[1] = '0' + ((v
/ 10) % 10);
1853 headingstr
[2] = '0' + (v
% 10);
1855 write_string(headingstr
, x
+ 1, majtick_start
+ textoffset
+ 2, 0, 0, TEXT_VA_MIDDLE
, TEXT_HA_CENTER
, 1, 3);
1857 // CORE draw routines end here
1859 void draw_artificial_horizon(float angle
, float pitch
, int16_t l_x
, int16_t l_y
, int16_t size
)
1862 uint8_t vertical
= 0, horizontal
= 0;
1867 alpha
= DEG2RAD(angle
);
1868 refx
= l_x
+ size
/ 2;
1869 refy
= l_y
+ size
/ 2;
1873 float dx
= sinf(alpha
) * (pitch
/ 90.0f
* (size
/ 2));
1874 float dy
= cosf(alpha
) * (pitch
/ 90.0f
* (size
/ 2));
1875 int16_t x0
= (size
/ 2) - dx
;
1876 int16_t y0
= (size
/ 2) + dy
;
1877 // calculate the line function
1878 if ((angle
< 90.0f
) && (angle
> -90)) {
1880 if (fabsf(angle
) < 1e-5f
) {
1889 // crossing point of line
1890 if (!vertical
&& !horizontal
) {
1893 int16_t y
= k
* (x
- x0
) + y0
;
1894 // find right crossing point
1899 x1
= ((y1
- y0
) + k
* x0
) / k
;
1903 x1
= ((y1
- y0
) + k
* x0
) / k
;
1905 // left crossing point
1907 y
= k
* (x
- x0
) + y0
;
1912 x2
= ((y2
- y0
) + k
* x0
) / k
;
1916 x2
= ((y2
- y0
) + k
* x0
) / k
;
1920 write_line_outlined(x1
+ l_x
, y1
+ l_y
, x2
+ l_x
, y2
+ l_y
, 0, 0, 0, 1);
1922 if (angle
<= 0.0f
&& angle
> -90.0f
) {
1923 // write_string("1", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1924 for (int i
= y2
; i
< size
; i
++) {
1925 x2
= ((i
- y0
) + k
* x0
) / k
;
1932 write_hline_lm(x2
+ l_x
, size
+ l_x
, i
+ l_y
, 1, 1);
1934 } else if (angle
< -90.0f
) {
1935 // write_string("2", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1936 for (int i
= 0; i
< y2
; i
++) {
1937 x2
= ((i
- y0
) + k
* x0
) / k
;
1944 write_hline_lm(size
+ l_x
, x2
+ l_x
, i
+ l_y
, 1, 1);
1946 } else if (angle
> 0.0f
&& angle
< 90.0f
) {
1947 // write_string("3", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1948 for (int i
= y1
; i
< size
; i
++) {
1949 x2
= ((i
- y0
) + k
* x0
) / k
;
1956 write_hline_lm(0 + l_x
, x2
+ l_x
, i
+ l_y
, 1, 1);
1958 } else if (angle
> 90.0f
) {
1959 // write_string("4", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1960 for (int i
= 0; i
< y1
; i
++) {
1961 x2
= ((i
- y0
) + k
* x0
) / k
;
1968 write_hline_lm(x2
+ l_x
, 0 + l_x
, i
+ l_y
, 1, 1);
1971 } else if (vertical
) {
1973 write_line_outlined(x0
+ l_x
, 0 + l_y
, x0
+ l_x
, size
+ l_y
, 0, 0, 0, 1);
1974 if (angle
>= 90.0f
) {
1975 // write_string("5", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1976 for (int i
= 0; i
< size
; i
++) {
1977 write_hline_lm(0 + l_x
, x0
+ l_x
, i
+ l_y
, 1, 1);
1980 // write_string("6", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1981 for (int i
= 0; i
< size
; i
++) {
1982 write_hline_lm(size
+ l_x
, x0
+ l_x
, i
+ l_y
, 1, 1);
1985 } else if (horizontal
) {
1987 write_hline_outlined(0 + l_x
, size
+ l_x
, y0
+ l_y
, 0, 0, 0, 1);
1989 // write_string("7", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1990 for (int i
= 0; i
< y0
; i
++) {
1991 write_hline_lm(0 + l_x
, size
+ l_x
, i
+ l_y
, 1, 1);
1994 // write_string("8", APPLY_HDEADBAND((GRAPHICS_RIGHT/2)),APPLY_VDEADBAND(GRAPHICS_BOTTOM-10), 0, 0, TEXT_VA_BOTTOM, TEXT_HA_CENTER, 0, 3);
1995 for (int i
= y0
; i
< size
; i
++) {
1996 write_hline_lm(0 + l_x
, size
+ l_x
, i
+ l_y
, 1, 1);
2002 write_line_outlined(l_x
, l_y
, l_x
, l_y
+ size
, 0, 0, 0, 1);
2003 write_line_outlined(l_x
+ size
, l_y
, l_x
+ size
, l_y
+ size
, 0, 0, 0, 1);
2005 write_line_outlined(refx
- 5, refy
, refx
+ 6, refy
, 0, 0, 0, 1);
2006 write_line_outlined(refx
, refy
, refx
, refy
- 3, 0, 0, 0, 1);
2011 write_string("ver 0.2", APPLY_HDEADBAND((GRAPHICS_RIGHT
/ 2)), APPLY_VDEADBAND(GRAPHICS_BOTTOM
- 10), 0, 0, TEXT_VA_BOTTOM
, TEXT_HA_CENTER
, 0, 3);
2014 void introGraphics()
2018 struct splashEntry splash_info
;
2020 splash_info
= splash
[image
];
2022 copyimage(APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2 - (splash_info
.width
) / 2), APPLY_VDEADBAND(GRAPHICS_BOTTOM
/ 2 - (splash_info
.height
) / 2), image
);
2025 drawBox(APPLY_HDEADBAND(0), APPLY_VDEADBAND(0), APPLY_HDEADBAND(GRAPHICS_RIGHT
- 8), APPLY_VDEADBAND(GRAPHICS_BOTTOM
));
2027 // Must mask out last half-word because SPI keeps clocking it out otherwise
2028 for (uint32_t i
= 0; i
< 8; i
++) {
2029 write_vline(draw_buffer_level
, GRAPHICS_WIDTH_REAL
- i
- 1, 0, GRAPHICS_HEIGHT_REAL
- 1, 0);
2030 write_vline(draw_buffer_mask
, GRAPHICS_WIDTH_REAL
- i
- 1, 0, GRAPHICS_HEIGHT_REAL
- 1, 0);
2034 void calcHomeArrow(int16_t m_yaw
)
2036 HomeLocationData home
;
2038 HomeLocationGet(&home
);
2039 GPSPositionSensorData gpsData
;
2040 GPSPositionSensorGet(&gpsData
);
2042 /** http://www.movable-type.co.uk/scripts/latlong.html **/
2043 float lat1
, lat2
, lon1
, lon2
, a
, c
, d
, x
, y
, brng
, u2g
;
2045 float gcsAlt
= home
.Altitude
; // Home MSL altitude
2046 float uavAlt
= gpsData
.Altitude
; // UAV MSL altitude
2047 float dAlt
= uavAlt
- gcsAlt
; // Altitude difference
2049 // Convert to radians
2050 lat1
= DEG2RAD(home
.Latitude
) / 10000000.0f
; // Home lat
2051 lon1
= DEG2RAD(home
.Longitude
) / 10000000.0f
; // Home lon
2052 lat2
= DEG2RAD(gpsData
.Latitude
) / 10000000.0f
; // UAV lat
2053 lon2
= DEG2RAD(gpsData
.Longitude
) / 10000000.0f
; // UAV lon
2057 var y = Math.sin(dLon) * Math.cos(lat2);
2058 var x = Math.cos(lat1)*Math.sin(lat2) -
2059 Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
2060 var brng = Math.atan2(y, x).toDeg();
2062 y
= sinf(lon2
- lon1
) * cosf(lat2
);
2063 x
= cosf(lat1
) * sinf(lat2
) - sinf(lat1
) * cosf(lat2
) * cosf(lon2
- lon1
);
2064 brng
= RAD2DEG(atan2f(y
, x
));
2069 // yaw corrected bearing, needs compass
2070 u2g
= brng
- 180.0f
- m_yaw
;
2075 // Haversine formula for distance
2078 var dLat = (lat2-lat1).toRad();
2079 var dLon = (lon2-lon1).toRad();
2080 var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
2081 Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
2082 Math.sin(dLon/2) * Math.sin(dLon/2);
2083 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
2086 a
= sinf((lat2
- lat1
) / 2) * sinf((lat2
- lat1
) / 2) + cosf(lat1
) * cosf(lat2
) * sinf((lon2
- lon1
) / 2) * sinf((lon2
- lon1
) / 2);
2087 c
= 2.0f
* atan2f(sqrtf(a
), sqrtf(1.0f
- a
));
2088 d
= 6371.0f
* 1000.0f
* c
;
2090 // Elevation v depends servo direction
2092 elevation
= 90.0f
- RAD2DEG(atanf(dAlt
/ d
));
2096 // ! TODO: sanity check
2100 sprintf(temp
, "hea:%d", (int)brng
);
2101 write_string(temp
, APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2 - 30), APPLY_VDEADBAND(30), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2102 sprintf(temp
, "ele:%d", (int)elevation
);
2103 write_string(temp
, APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2 - 30), APPLY_VDEADBAND(30 + 10), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2104 sprintf(temp
, "dis:%d", (int)d
);
2105 write_string(temp
, APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2 - 30), APPLY_VDEADBAND(30 + 10 + 10), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2106 sprintf(temp
, "u2g:%d", (int)u2g
);
2107 write_string(temp
, APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2 - 30), APPLY_VDEADBAND(30 + 10 + 10 + 10), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2109 sprintf(temp
, "%c%c", (int)(u2g
/ 22.5f
) * 2 + 0x90, (int)(u2g
/ 22.5f
) * 2 + 0x91);
2110 write_string(temp
, APPLY_HDEADBAND(250), APPLY_VDEADBAND(40 + 10 + 10), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 3);
2114 int lama_loc
[2][30];
2122 if (lama
% 10 == 0) {
2123 for (int z
= 0; z
< 30; z
++) {
2124 lama_loc
[0][z
] = rand() % (GRAPHICS_RIGHT
- 10);
2125 lama_loc
[1][z
] = rand() % (GRAPHICS_BOTTOM
- 10);
2128 for (int z
= 0; z
< 30; z
++) {
2129 sprintf(temp
, "%c", 0xe8 + (lama_loc
[0][z
] % 2));
2130 write_string(temp
, APPLY_HDEADBAND(lama_loc
[0][z
]), APPLY_VDEADBAND(lama_loc
[1][z
]), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2134 // main draw function
2135 void updateGraphics()
2137 OsdSettingsData OsdSettings
;
2139 OsdSettingsGet(&OsdSettings
);
2140 AttitudeStateData attitude
;
2141 AttitudeStateGet(&attitude
);
2142 GPSPositionSensorData gpsData
;
2143 GPSPositionSensorGet(&gpsData
);
2144 HomeLocationData home
;
2145 HomeLocationGet(&home
);
2146 BaroSensorData baro
;
2147 BaroSensorGet(&baro
);
2148 FlightStatusData status
;
2149 FlightStatusGet(&status
);
2151 PIOS_Servo_Set(0, OsdSettings
.White
);
2152 PIOS_Servo_Set(1, OsdSettings
.Black
);
2154 switch (OsdSettings
.Screen
) {
2155 case 0: // Dave simple
2157 if (home
.Set
== HOMELOCATION_SET_FALSE
) {
2160 sprintf(temps
, "HOME NOT SET");
2161 // printTextFB(x,y,temp);
2162 write_string(temps
, APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2), (GRAPHICS_BOTTOM
/ 2), 0, 0, TEXT_VA_TOP
, TEXT_HA_CENTER
, 0, 3);
2167 memset(temp
, ' ', 40);
2168 // Note: cast to double required due to -Wdouble-promotion compiler option is
2169 // being used, and there is no way in C to pass a float to a variadic function like sprintf()
2170 sprintf(temp
, "Lat:%11.7f", (double)(gpsData
.Latitude
/ 10000000.0f
));
2171 write_string(temp
, APPLY_HDEADBAND(20), APPLY_VDEADBAND(GRAPHICS_BOTTOM
- 30), 0, 0, TEXT_VA_BOTTOM
, TEXT_HA_LEFT
, 0, 3);
2172 sprintf(temp
, "Lon:%11.7f", (double)(gpsData
.Longitude
/ 10000000.0f
));
2173 write_string(temp
, APPLY_HDEADBAND(20), APPLY_VDEADBAND(GRAPHICS_BOTTOM
- 10), 0, 0, TEXT_VA_BOTTOM
, TEXT_HA_LEFT
, 0, 3);
2174 sprintf(temp
, "Sat:%d", (int)gpsData
.Satellites
);
2175 write_string(temp
, APPLY_HDEADBAND(GRAPHICS_RIGHT
- 40), APPLY_VDEADBAND(30), 0, 0, TEXT_VA_TOP
, TEXT_HA_RIGHT
, 0, 2);
2177 /* Print ADC voltage FLIGHT*/
2178 sprintf(temp
, "V:%5.2fV", (double)(PIOS_ADC_PinGet(2) * 3 * 6.1f
/ 4096));
2179 write_string(temp
, APPLY_HDEADBAND(20), APPLY_VDEADBAND(20), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 3);
2181 if (gpsData
.Heading
> 180) {
2182 calcHomeArrow((int16_t)(gpsData
.Heading
- 360));
2184 calcHomeArrow((int16_t)(gpsData
.Heading
));
2190 /*drawBox(2,2,GRAPHICS_WIDTH_REAL-4,GRAPHICS_HEIGHT_REAL-4);
2191 write_filled_rectangle(draw_buffer_mask,0,0,GRAPHICS_WIDTH_REAL-2,GRAPHICS_HEIGHT_REAL-2,0);
2192 write_filled_rectangle(draw_buffer_mask,2,2,GRAPHICS_WIDTH_REAL-4-2,GRAPHICS_HEIGHT_REAL-4-2,2);
2193 write_filled_rectangle(draw_buffer_mask,3,3,GRAPHICS_WIDTH_REAL-4-1,GRAPHICS_HEIGHT_REAL-4-1,0);*/
2194 // write_filled_rectangle(draw_buffer_mask,5,5,GRAPHICS_WIDTH_REAL-4-5,GRAPHICS_HEIGHT_REAL-4-5,0);
2195 // write_rectangle_outlined(10,10,GRAPHICS_WIDTH_REAL-20,GRAPHICS_HEIGHT_REAL-20,0,0);
2196 // drawLine(GRAPHICS_WIDTH_REAL-1, GRAPHICS_HEIGHT_REAL-1,(GRAPHICS_WIDTH_REAL/2)-1, GRAPHICS_HEIGHT_REAL-1 );
2197 // drawCircle((GRAPHICS_WIDTH_REAL/2)-1, (GRAPHICS_HEIGHT_REAL/2)-1, (GRAPHICS_HEIGHT_REAL/2)-1);
2198 // drawCircle((GRAPHICS_SIZE/2)-1, (GRAPHICS_SIZE/2)-1, (GRAPHICS_SIZE/2)-2);
2199 // drawLine(0, (GRAPHICS_SIZE/2)-1, GRAPHICS_SIZE-1, (GRAPHICS_SIZE/2)-1);
2200 // drawLine((GRAPHICS_SIZE/2)-1, 0, (GRAPHICS_SIZE/2)-1, GRAPHICS_SIZE-1);
2214 if (gpsData
.Heading
> 180) {
2215 calcHomeArrow((int16_t)(gpsData
.Heading
- 360));
2217 calcHomeArrow((int16_t)(gpsData
.Heading
));
2220 /* Draw Attitude Indicator */
2221 if (OsdSettings
.Attitude
== OSDSETTINGS_ATTITUDE_ENABLED
) {
2222 drawAttitude(APPLY_HDEADBAND(OsdSettings
.AttitudeSetup
.X
),
2223 APPLY_VDEADBAND(OsdSettings
.AttitudeSetup
.Y
), attitude
.Pitch
, attitude
.Roll
, 96);
2225 // write_string("Hello OP-OSD", 60, 12, 1, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, 0);
2226 // printText16( 60, 12,"Hello OP-OSD");
2230 memset(temp
, ' ', 40);
2231 sprintf(temp
, "Lat:%11.7f", (double)(gpsData
.Latitude
/ 10000000.0f
));
2232 write_string(temp
, APPLY_HDEADBAND(5), APPLY_VDEADBAND(5), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2233 sprintf(temp
, "Lon:%11.7f", (double)(gpsData
.Longitude
/ 10000000.0f
));
2234 write_string(temp
, APPLY_HDEADBAND(5), APPLY_VDEADBAND(15), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2235 sprintf(temp
, "Fix:%d", (int)gpsData
.Status
);
2236 write_string(temp
, APPLY_HDEADBAND(5), APPLY_VDEADBAND(25), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2237 sprintf(temp
, "Sat:%d", (int)gpsData
.Satellites
);
2238 write_string(temp
, APPLY_HDEADBAND(5), APPLY_VDEADBAND(35), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2240 /* Print RTC time */
2241 if (OsdSettings
.Time
== OSDSETTINGS_TIME_ENABLED
) {
2242 printTime(APPLY_HDEADBAND(OsdSettings
.TimeSetup
.X
), APPLY_VDEADBAND(OsdSettings
.TimeSetup
.Y
));
2245 /* Print Number of detected video Lines */
2246 sprintf(temp
, "Lines:%4d", PIOS_Video_GetOSDLines());
2247 write_string(temp
, APPLY_HDEADBAND((GRAPHICS_RIGHT
- 8)), APPLY_VDEADBAND(5), 0, 0, TEXT_VA_TOP
, TEXT_HA_RIGHT
, 0, 2);
2249 /* Print ADC voltage */
2250 // sprintf(temp,"Rssi:%4dV",(int)(PIOS_ADC_PinGet(4)*3000/4096));
2251 // write_string(temp, (GRAPHICS_WIDTH_REAL - 2),15, 0, 0, TEXT_VA_TOP, TEXT_HA_RIGHT, 0, 2);
2252 sprintf(temp
, "Rssi:%4.2fV", (double)(PIOS_ADC_PinGet(5) * 3.0f
/ 4096.0f
));
2253 write_string(temp
, APPLY_HDEADBAND((GRAPHICS_RIGHT
- 8)), APPLY_VDEADBAND(15), 0, 0, TEXT_VA_TOP
, TEXT_HA_RIGHT
, 0, 2);
2255 /* Print CPU temperature */
2256 sprintf(temp
, "Temp:%4.2fC", (double)(PIOS_ADC_PinGet(3) * 0.29296875f
- 264));
2257 write_string(temp
, APPLY_HDEADBAND((GRAPHICS_RIGHT
- 8)), APPLY_VDEADBAND(25), 0, 0, TEXT_VA_TOP
, TEXT_HA_RIGHT
, 0, 2);
2259 /* Print ADC voltage FLIGHT*/
2260 sprintf(temp
, "FltV:%4.2fV", (double)(PIOS_ADC_PinGet(2) * 3.0f
* 6.1f
/ 4096.0f
));
2261 write_string(temp
, APPLY_HDEADBAND((GRAPHICS_RIGHT
- 8)), APPLY_VDEADBAND(35), 0, 0, TEXT_VA_TOP
, TEXT_HA_RIGHT
, 0, 2);
2263 /* Print ADC voltage VIDEO*/
2264 sprintf(temp
, "VidV:%4.2fV", (double)(PIOS_ADC_PinGet(4) * 3.0f
* 6.1f
/ 4096.0f
));
2265 write_string(temp
, APPLY_HDEADBAND((GRAPHICS_RIGHT
- 8)), APPLY_VDEADBAND(45), 0, 0, TEXT_VA_TOP
, TEXT_HA_RIGHT
, 0, 2);
2267 /* Print ADC voltage RSSI */
2268 // sprintf(temp,"Curr:%4dA",(int)(PIOS_ADC_PinGet(0)*300*61/4096));
2269 // write_string(temp, (GRAPHICS_WIDTH_REAL - 2),60, 0, 0, TEXT_VA_TOP, TEXT_HA_RIGHT, 0, 2);
2270 /* Draw Battery Gauge */
2286 /*if(OsdSettings.Battery == OSDSETTINGS_BATTERY_ENABLED)
2288 drawBattery(APPLY_HDEADBAND(OsdSettings.BatterySetup[OSDSETTINGS_BATTERYSETUP_X]),APPLY_VDEADBAND(OsdSettings.BatterySetup[OSDSETTINGS_BATTERYSETUP_Y]),m_batt,16);
2291 // drawAltitude(200,50,m_alt,dir);
2292 // drawArrow(96,GRAPHICS_HEIGHT_REAL/2,angleB,32);
2293 // Draw airspeed (left side.)
2294 if (OsdSettings
.Speed
== OSDSETTINGS_SPEED_ENABLED
) {
2295 hud_draw_vertical_scale((int)gpsData
.Groundspeed
, 100, -1, APPLY_HDEADBAND(OsdSettings
.SpeedSetup
.X
),
2296 APPLY_VDEADBAND(OsdSettings
.SpeedSetup
.Y
), 100, 10, 20, 7, 12, 15, 1000, HUD_VSCALE_FLAG_NO_NEGATIVE
);
2298 // Draw altimeter (right side.)
2299 if (OsdSettings
.Altitude
== OSDSETTINGS_ALTITUDE_ENABLED
) {
2300 hud_draw_vertical_scale((int)gpsData
.Altitude
, 200, +1, APPLY_HDEADBAND(OsdSettings
.AltitudeSetup
.X
),
2301 APPLY_VDEADBAND(OsdSettings
.AltitudeSetup
.Y
), 100, 20, 100, 7, 12, 15, 500, 0);
2304 if (OsdSettings
.Heading
== OSDSETTINGS_HEADING_ENABLED
) {
2305 if (attitude
.Yaw
< 0) {
2306 hud_draw_linear_compass(360 + attitude
.Yaw
, 150, 120, APPLY_HDEADBAND(OsdSettings
.HeadingSetup
.X
),
2307 APPLY_VDEADBAND(OsdSettings
.HeadingSetup
.Y
), 15, 30, 7, 12, 0);
2309 hud_draw_linear_compass(attitude
.Yaw
, 150, 120, APPLY_HDEADBAND(OsdSettings
.HeadingSetup
.X
),
2310 APPLY_VDEADBAND(OsdSettings
.HeadingSetup
.Y
), 15, 30, 7, 12, 0);
2318 int x
= ((GRAPHICS_RIGHT
/ 2) - (size
/ 2)), y
= (GRAPHICS_BOTTOM
- size
- 2);
2319 draw_artificial_horizon(-attitude
.Roll
, attitude
.Pitch
, APPLY_HDEADBAND(x
), APPLY_VDEADBAND(y
), size
);
2320 hud_draw_vertical_scale((int)gpsData
.Groundspeed
, 20, +1, APPLY_HDEADBAND(GRAPHICS_RIGHT
- (x
- 1)), APPLY_VDEADBAND(y
+ (size
/ 2)), size
, 5, 10, 4, 7,
2321 10, 100, HUD_VSCALE_FLAG_NO_NEGATIVE
);
2322 if (OsdSettings
.AltitudeSource
== OSDSETTINGS_ALTITUDESOURCE_BARO
) {
2323 hud_draw_vertical_scale((int)baro
.Altitude
, 50, -1, APPLY_HDEADBAND((x
+ size
+ 1)), APPLY_VDEADBAND(y
+ (size
/ 2)), size
, 10, 20, 4, 7, 10, 500, 0);
2325 hud_draw_vertical_scale((int)gpsData
.Altitude
, 50, -1, APPLY_HDEADBAND((x
+ size
+ 1)), APPLY_VDEADBAND(y
+ (size
/ 2)), size
, 10, 20, 4, 7, 10, 500,
2331 memset(temp
, ' ', 50);
2332 switch (status
.FlightMode
) {
2333 case FLIGHTSTATUS_FLIGHTMODE_MANUAL
:
2334 sprintf(temp
, "Man");
2336 case FLIGHTSTATUS_FLIGHTMODE_STABILIZED1
:
2337 sprintf(temp
, "Stab1");
2339 case FLIGHTSTATUS_FLIGHTMODE_STABILIZED2
:
2340 sprintf(temp
, "Stab2");
2342 case FLIGHTSTATUS_FLIGHTMODE_STABILIZED3
:
2343 sprintf(temp
, "Stab3");
2345 case FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD
:
2346 sprintf(temp
, "PH");
2348 case FLIGHTSTATUS_FLIGHTMODE_RETURNTOBASE
:
2349 sprintf(temp
, "RTB");
2351 case FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER
:
2352 sprintf(temp
, "PATH");
2355 sprintf(temp
, "Mode: %d", status
.FlightMode
);
2358 write_string(temp
, APPLY_HDEADBAND(5), APPLY_VDEADBAND(5), 0, 0, TEXT_VA_TOP
, TEXT_HA_LEFT
, 0, 2);
2370 int image
= OsdSettings
.Screen
- 4;
2371 struct splashEntry splash_info
;
2372 splash_info
= splash
[image
];
2374 copyimage(APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2 - (splash_info
.width
) / 2), APPLY_VDEADBAND(GRAPHICS_BOTTOM
/ 2 - (splash_info
.height
) / 2), image
);
2378 write_vline_lm(APPLY_HDEADBAND(GRAPHICS_RIGHT
/ 2), APPLY_VDEADBAND(0), APPLY_VDEADBAND(GRAPHICS_BOTTOM
), 1, 1);
2379 write_hline_lm(APPLY_HDEADBAND(0), APPLY_HDEADBAND(GRAPHICS_RIGHT
), APPLY_VDEADBAND(GRAPHICS_BOTTOM
/ 2), 1, 1);
2383 // Must mask out last half-word because SPI keeps clocking it out otherwise
2384 for (uint32_t i
= 0; i
< 8; i
++) {
2385 write_vline(draw_buffer_level
, GRAPHICS_WIDTH_REAL
- i
- 1, 0, GRAPHICS_HEIGHT_REAL
- 1, 0);
2386 write_vline(draw_buffer_mask
, GRAPHICS_WIDTH_REAL
- i
- 1, 0, GRAPHICS_HEIGHT_REAL
- 1, 0);
2390 void updateOnceEveryFrame()
2398 * Initialise the gps module
2399 * \return -1 if initialisation failed
2400 * \return 0 on success
2403 int32_t osdgenStart(void)
2406 vSemaphoreCreateBinary(osdSemaphore
);
2407 xTaskCreate(osdgenTask
, "OSDGEN", STACK_SIZE_BYTES
/ 4, NULL
, TASK_PRIORITY
, &osdgenTaskHandle
);
2408 PIOS_TASK_MONITOR_RegisterTask(TASKINFO_RUNNING_OSDGEN
, osdgenTaskHandle
);
2409 #ifdef PIOS_INCLUDE_WDG
2410 PIOS_WDG_RegisterFlag(PIOS_WDG_OSDGEN
);
2416 * Initialise the osd module
2417 * \return -1 if initialisation failed
2418 * \return 0 on success
2420 int32_t osdgenInitialize(void)
2422 AttitudeStateInitialize();
2423 #ifdef PIOS_INCLUDE_GPS
2424 GPSPositionSensorInitialize();
2425 #if !defined(PIOS_GPS_MINIMAL)
2426 GPSTimeInitialize();
2427 GPSSatellitesInitialize();
2429 #ifdef PIOS_GPS_SETS_HOMELOCATION
2430 HomeLocationInitialize();
2433 OsdSettingsInitialize();
2434 BaroSensorInitialize();
2435 FlightStatusInitialize();
2439 MODULE_INITCALL(osdgenInitialize
, osdgenStart
);
2443 * Main osd task. It does not return.
2446 static void osdgenTask(__attribute__((unused
)) void *parameters
)
2448 // portTickType lastSysTime;
2450 // lastSysTime = xTaskGetTickCount();
2451 OsdSettingsData OsdSettings
;
2453 OsdSettingsGet(&OsdSettings
);
2455 PIOS_Servo_Set(0, OsdSettings
.White
);
2456 PIOS_Servo_Set(1, OsdSettings
.Black
);
2459 for (int i
= 0; i
< 63; i
++) {
2460 if (xSemaphoreTake(osdSemaphore
, LONG_TIME
) == pdTRUE
) {
2461 #ifdef PIOS_INCLUDE_WDG
2462 PIOS_WDG_UpdateFlag(PIOS_WDG_OSDGEN
);
2468 for (int i
= 0; i
< 63; i
++) {
2469 if (xSemaphoreTake(osdSemaphore
, LONG_TIME
) == pdTRUE
) {
2470 #ifdef PIOS_INCLUDE_WDG
2471 PIOS_WDG_UpdateFlag(PIOS_WDG_OSDGEN
);
2480 if (xSemaphoreTake(osdSemaphore
, LONG_TIME
) == pdTRUE
) {
2481 #ifdef PIOS_INCLUDE_WDG
2482 PIOS_WDG_UpdateFlag(PIOS_WDG_OSDGEN
);
2484 updateOnceEveryFrame();
2486 // xSemaphoreTake(osdSemaphore, portMAX_DELAY);
2487 // vTaskDelayUntil(&lastSysTime, 10 / portTICK_RATE_MS);