Subversion Repositories Projects

Rev

Rev 377 | Rev 379 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
321 cascade 1
/****************************************************************************
2
 *   Copyright (C) 2009 by Claas Anders "CaScAdE" Rathje                    *
3
 *   admiralcascade@gmail.com                                               *
4
 *   Project-URL: http://www.mylifesucks.de/oss/c-osd/                      *
5
 *                                                                          *
6
 *   This program 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 of the License.         *
9
 *                                                                          *
10
 *   This program is distributed in the hope that it will be useful,        *
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
13
 *   GNU General Public License for more details.                           *
14
 *                                                                          *
15
 *   You should have received a copy of the GNU General Public License      *
16
 *   along with this program; if not, write to the                          *
17
 *   Free Software Foundation, Inc.,                                        *
18
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.              *
19
 *                                                                          *
20
 *                                                                          *
21
 *   Credits to:                                                            *
22
 *   Holger Buss & Ingo Busker from mikrokopter.de for the MK project       *
23
 *   Gregor "killagreg" Stobrawa for making the MK code readable            *
24
 *   Klaus "akku" Buettner for the hardware                                 *
25
 *   Manuel "KeyOz" Schrape for explaining the MK protocol to me            *
26
 ****************************************************************************/
27
 
28
#include <avr/io.h>
29
#include <avr/interrupt.h>
30
#include <util/delay.h>
346 cascade 31
#include <avr/pgmspace.h> 
32
#include "main.h"
33
#include "max7456_software_spi.h"
331 cascade 34
#include "usart1.h"
321 cascade 35
 
36
/* TODO:
37
 * - verifiy correctness of values
324 cascade 38
 * - clean up code :)
321 cascade 39
 */
40
 
329 cascade 41
#if !(ALLCHARSDEBUG|(WRITECHARS != -1))
346 cascade 42
// data structs not needed for character flashin
331 cascade 43
#include "mk-data-structs.h"
321 cascade 44
 
45
/* ##########################################################################
46
 * global definitions and global vars
47
 * ##########################################################################*/
346 cascade 48
 
321 cascade 49
volatile uint16_t setsReceived = 0;
50
 
51
volatile NaviData_t naviData;
52
volatile DebugOut_t debugData;
53
 
54
// cache old vars for blinking attribute, checkup is faster than full
55
// attribute write each time
56
volatile uint8_t last_UBat = 255;
57
volatile uint8_t last_RC_Quality = 255;
58
 
59
// 16bit should be enough, normal LiPos don't last that long
60
volatile uint16_t uptime = 0;
61
volatile uint16_t timer = 0;
62
 
331 cascade 63
// remember last time data was received
64
volatile uint8_t seconds_since_last_data = 0;
65
 
346 cascade 66
// store stats description in progmem to save space
67
char stats_item_0[] PROGMEM = "max Altitude:";
68
char stats_item_1[] PROGMEM = "max Speed   :";
69
char stats_item_2[] PROGMEM = "max Distance:";
70
char stats_item_3[] PROGMEM = "min voltage :";
71
char stats_item_4[] PROGMEM = "max time    :";
72
char* stats_item_pointers[] PROGMEM = {stats_item_0, stats_item_1, stats_item_2, stats_item_3, stats_item_4};
73
 
74
// store more fixed strings in progmen
75
char ON[]  PROGMEM = "ON ";
76
char OFF[] PROGMEM = "OFF";
77
 
329 cascade 78
#endif // ends !(ALLCHARSDEBUG|(WRITECHARS != -1))
326 cascade 79
 
80
// general PAL|NTSC distingiusch stuff
81
uint8_t top_line = 1;
82
uint8_t bottom_line = 14;
83
 
84
// Flags
85
uint8_t COSD_FLAGS = 0;
86
 
321 cascade 87
/* ##########################################################################
326 cascade 88
 * debounce buttons
89
 * ##########################################################################*/
90
int s1_pressed() {
91
        if (S1_PRESSED) {
92
                _delay_ms(25);
93
                if (S1_PRESSED) return 1;
94
        }
95
        return 0;
96
}
97
 
98
int s2_pressed() {
99
        if (S2_PRESSED) {
100
                _delay_ms(25);
101
                if (S2_PRESSED) return 1;
102
        }
103
        return 0;
104
}
105
 
321 cascade 106
 
329 cascade 107
#if !(ALLCHARSDEBUG|(WRITECHARS != -1))
321 cascade 108
 
109
/**
331 cascade 110
 * serial support
321 cascade 111
 */
346 cascade 112
//#include "usart1.c"
321 cascade 113
 
114
 
115
/* ##########################################################################
116
 * timer stuff
117
 * ##########################################################################*/
118
 
331 cascade 119
/**
120
 * timer kicks in every 1000uS ^= 1ms
321 cascade 121
 */
122
ISR(TIMER0_OVF_vect) {
123
    OCR0 = 6; // preload
124
    if (!timer--) {
125
        uptime++;
126
        timer = 999;
331 cascade 127
                seconds_since_last_data++;
321 cascade 128
    }
129
}
130
 
131
/* ##########################################################################
132
 * compass stuff
133
 * ##########################################################################*/
134
 
135
/**
136
 * convert the <heading> gotton from NC into an index
137
 */
138
uint8_t heading_conv(uint16_t heading) {
139
    if (heading > 23 && heading < 68) {
140
        //direction = "NE";
141
        return 0;
142
    } else if (heading > 67 && heading < 113) {
143
        //direction = "E ";
144
        return 1;
145
    } else if (heading > 112 && heading < 158) {
146
        //direction = "SE";
147
        return 2;
148
    } else if (heading > 157 && heading < 203) {
149
        //direction = "S ";
150
        return 3;
151
    } else if (heading > 202 && heading < 248) {
152
        //direction = "SW";
153
        return 4;
154
    } else if (heading > 247 && heading < 293) {
155
        //direction = "W ";
156
        return 5;
157
    } else if (heading > 292 && heading < 338) {
158
        //direction = "NW";
159
        return 6;
160
    }
161
    //direction = "N ";
162
    return 7;
163
}
164
 
165
/**
377 cascade 166
 * convert the <heading> gotton from NC into a more
167
 * precise index
168
 */
169
uint8_t heading_fine_conv(uint16_t heading) {
170
        if (heading > 337) return 0;
171
        return (heading * 10) / 225;
172
}
173
 
174
/**
321 cascade 175
 * draw a compass rose at <x>/<y> for <heading>
176
 */
177
void draw_compass(uint8_t x, uint8_t y, uint16_t heading) {
178
    //char* rose = "---N---O---S---W---N---O---S---W---N---O---S---W";
179
    char rose[48] = {216, 215, 216, 211, 216, 215, 216, 213, 216, 215, 216, 212,
180
                    216, 215, 216, 214, 216, 215, 216, 211, 216, 215, 216, 213,
181
                    216, 215, 216, 212, 216, 215, 216, 214, 216, 215, 216, 211,
182
                    216, 215, 216, 213, 216, 215, 216, 212, 216, 215, 216, 214};
183
        // the center is char 19 (north), we add the current heading in 8th
184
        // which would be 22.5 degrees, but float would bloat up the code
185
        // and *10 / 225 would take ages... so we take the uncorrect way
186
    uint8_t front = 19 + (heading / 22);
187
    for (uint8_t i = 0; i < 9; i++) {
188
                write_char_xy(x++, y, rose[front - 4 + i]);
189
    }
190
}
191
 
192
/* ##########################################################################
377 cascade 193
 * battery index
194
 * ##########################################################################*/
195
/**
196
 * draw a battery symbol at <x>/<y> according to <voltage>
197
 */
198
void draw_battery(uint8_t x, uint8_t y, uint16_t voltage) {
199
        uint8_t percent = (100* (voltage - UBAT_WRN) / (UBAT_MAX - UBAT_WRN));
200
        if (percent > 100) percent = 100;
378 cascade 201
        if (voltage < UBAT_WRN) percent = 0;
377 cascade 202
        write_char_xy(x, y, 0x9d - (percent * 13 / 100));
203
        //write_ndigit_number_u(x, y-1, percent * 13 / 100, 100, 0);
204
}
205
 
206
/**
207
 * draw variometer arrows at <x>/<y> according to <variometer>
208
 */
209
void draw_variometer(uint8_t x, uint8_t y, int16_t variometer) {
210
        if (variometer == 0) {
211
                write_char_xy(x, y, 0xbb); // plain line
212
        } else if (variometer > 0) { // gain height
213
                switch (variometer / 5){
214
                        case 0:
215
                                write_char_xy(x, y, 0xba); // smallest arrow up
216
                                break;
217
                        case 1:
218
                                write_char_xy(x, y, 0xb9); // small arrow up
219
                                break;
220
                        case 2:
221
                                write_char_xy(x, y, 0xb8); // large arrow up
222
                                break;
223
                        default:
224
                                write_char_xy(x, y, 0xb7); // largest arrow up
225
                }
226
        } else { // sink
227
                switch (variometer / -5){
228
                        case 0:
229
                                write_char_xy(x, y, 0xbc); // smallest arrow down
230
                                break;
231
                        case 1:
232
                                write_char_xy(x, y, 0xbd); // small arrow down
233
                                break;
234
                        case 2:
235
                                write_char_xy(x, y, 0xbe); // large arrow down
236
                                break;
237
                        default:
238
                                write_char_xy(x, y, 0xbf); // largest arrow down
239
                }
240
        }
241
}
242
 
243
/* ##########################################################################
321 cascade 244
 * artificial horizon
245
 * ##########################################################################*/
246
// remember last time displayed values
247
int8_t old_af_x = -1, old_af_y = -1;
248
 
249
/**
250
 * draw roll und nick indicators (could be enhanced to full artificial horizon)
251
 * from line <firstline> to <listlines> for given <nick> and <roll> values
252
 */
253
void draw_artificial_horizon(uint8_t firstline, uint8_t lastline, int16_t nick, int16_t roll) {
254
        char noodle[5] = {225, 225, 226, 227, 227};
255
        uint8_t center_x = 15;
256
        uint8_t center_y = lastline - firstline;
257
        center_y = 7;
258
        write_char_xy(center_x,center_y,228);
259
        uint8_t cpos, nicky, rollx;
260
 
261
        // which line
262
        int8_t ypos =  nick / 20;
263
        // which character from the array?
264
        if (nick < 0) {
265
                cpos = -1*((nick - (ypos * 20))/4);
266
                ypos--;
267
        } else cpos = 4-((nick - (ypos * 20))/4);
268
        if (cpos > 4) cpos = 4;
269
 
270
        nicky = center_y - ypos;
271
        if (nicky > lastline) nicky = lastline;
272
        else if (nicky < firstline) nicky = firstline;
273
 
274
        // ensure roll-borders
275
        rollx = (roll / 8)+15;
276
        if (rollx < 2) rollx = 2;
277
        else if (rollx > 28) rollx = 28;
278
 
279
 
280
        // clear roll
281
        if (old_af_x != rollx && old_af_x >= 0) {
282
                write_char_xy(old_af_x,13,0);
283
        }
284
 
285
        // clear nick
286
        if (old_af_y != nicky && old_af_y >= 0) {
287
                write_char_xy(center_x-1,old_af_y,0);
288
                write_char_xy(center_x+1,old_af_y,0);
289
        }
290
 
291
 
292
        // draw nick
293
        write_char_xy(center_x-1,nicky,noodle[cpos]);
294
        write_char_xy(center_x+1,nicky,noodle[cpos]);
295
 
296
        // draw roll
297
        write_char_xy(rollx,lastline,229);
298
 
299
        // update old vars
300
        old_af_x = rollx;
301
        old_af_y = nicky;
302
 
303
        // debug numbers
304
        //write_3digit_number_u(20,6,cpos);
305
        //write_number_s(20,7,ypos);    
306
        //write_number_s(0,7,nick);             
307
        //write_number_s(18,11,roll);   
308
}
309
 
326 cascade 310
/* ##########################################################################
311
 * A simple config menu for the flags
312
 * ##########################################################################*/
339 cascade 313
 
314
/**
315
 * helper function for menu updating
316
 */
317
void config_menu_drawings(uint8_t chosen) {
318
    // clear prevoius _cursor_
346 cascade 319
    write_ascii_string(3, (chosen + 6) % 7, " ");
339 cascade 320
    // draw current _cursor_
321
    write_ascii_string(3, chosen + 6, ">");
322
    if (COSD_FLAGS & COSD_FLAG_HUD) {
346 cascade 323
        write_ascii_string_pgm(23, 6, ON);
339 cascade 324
    } else {
346 cascade 325
                write_ascii_string_pgm(23, 6, OFF);
339 cascade 326
    }
327
    if (COSD_FLAGS & COSD_FLAG_ARTHORIZON) {
346 cascade 328
        write_ascii_string_pgm(23, 7, ON);
339 cascade 329
    } else {
346 cascade 330
        write_ascii_string_pgm(23, 7, OFF);
339 cascade 331
    }
332
        if (COSD_FLAGS & COSD_FLAG_STATS) {
346 cascade 333
        write_ascii_string_pgm(23, 8, ON);
339 cascade 334
    } else {
346 cascade 335
        write_ascii_string_pgm(23, 8, OFF);
339 cascade 336
    }
337
    if (COSD_FLAGS & COSD_FLAG_WARNINGS) {
346 cascade 338
        write_ascii_string_pgm(23, 9, ON);
339 cascade 339
    } else {
346 cascade 340
        write_ascii_string_pgm(23, 9, OFF);
339 cascade 341
    }
342
}
343
 
344
/**
346 cascade 345
 * some sort of clicking response in the menu
346
 */
347
void config_menu_doclick(uint8_t chosen, char** menu) {
348
        write_ascii_string(4, chosen + 6, "DONE              ");
349
        _delay_ms(1000);
350
        write_ascii_string(4, chosen + 6, menu[chosen]);
351
}
352
 
353
/**
339 cascade 354
 * a simple config menu tryout
355
 */
326 cascade 356
void config_menu(void) {
357
        // disable interrupts (makes the menu more smoothely)
358
        cli();
321 cascade 359
 
326 cascade 360
        // clear screen
361
        clear();
362
 
346 cascade 363
        char* menu[8] = {"Full HUD",
339 cascade 364
                                         "Art.Horizon in HUD",
365
                                         "Statistics",
366
                                         "Warnings",    // TODO: do it!
346 cascade 367
                                         "Reset uptime",
368
                                         "Request OSD-data",
369
                                         "Disable Debug-data",
339 cascade 370
                                         "EXIT"};
326 cascade 371
 
372
        uint8_t inmenu = 1;
373
        uint8_t chosen = 0;
339 cascade 374
        write_ascii_string(6,  2, "C-OSD Config Menu");
326 cascade 375
 
376
        // wait a bit before doing stuff so user has chance to release button
377
        _delay_ms(250);
378
 
339 cascade 379
        write_ascii_string(4,  6, menu[0]);
380
        write_ascii_string(4,  7, menu[1]);
381
        write_ascii_string(4,  8, menu[2]);
382
        write_ascii_string(4,  9, menu[3]);
383
        write_ascii_string(4, 10, menu[4]);
346 cascade 384
        write_ascii_string(4, 11, menu[5]);
385
        write_ascii_string(4, 12, menu[6]);
386
        write_ascii_string(4, 13, menu[7]);
339 cascade 387
 
388
        config_menu_drawings(chosen);
389
 
326 cascade 390
        while (inmenu) {
391
                        if (s2_pressed()) {
339 cascade 392
                                write_ascii_string(3,  chosen+6, " ");
346 cascade 393
                                chosen = (chosen + 1) % 8;
339 cascade 394
                                write_ascii_string(3,  chosen+6, ">");
326 cascade 395
                                _delay_ms(500);
396
                        } else if (s1_pressed()) {
397
                                switch (chosen) {
339 cascade 398
                                        case 0:         // full HUD
399
                                                COSD_FLAGS ^= COSD_FLAG_HUD;
400
                                                config_menu_drawings(chosen);
326 cascade 401
                                                break;
339 cascade 402
                                        case 1:         // art horizon
403
                                                COSD_FLAGS ^= COSD_FLAG_ARTHORIZON;
404
                                                config_menu_drawings(chosen);
326 cascade 405
                                                break;
339 cascade 406
                                        case 2:         // statistics
407
                                                COSD_FLAGS ^= COSD_FLAG_STATS;
408
                                                config_menu_drawings(chosen);
326 cascade 409
                                                break;
339 cascade 410
                                        case 3:         // warnings
411
                                                COSD_FLAGS ^= COSD_FLAG_WARNINGS;
412
                                                config_menu_drawings(chosen);
413
                                                break;
346 cascade 414
                                        case 4:         // reset uptime
415
                                                uptime = 0;
416
                                                config_menu_doclick(chosen, menu);
417
                                                break;
418
                                        case 5:         // re-request OSD data
419
                                                // request OSD Data from NC every 100ms
420
                                                usart1_request_mk_data(1, 'o', 100);
421
                                                config_menu_doclick(chosen, menu);
422
                                                break;
423
                                        case 6:         // disable debug data
424
                                                // disable sending of debug data
425
                                                // may result in smoother ddata display
426
                                                usart1_request_mk_data(0, 'd', 0);
427
                                                config_menu_doclick(chosen, menu);
428
                                                break;
429
                                        case 7:         // exit
339 cascade 430
                                                inmenu = 0;
431
                                                break;
326 cascade 432
                                }
339 cascade 433
                                _delay_ms(250);
326 cascade 434
                        }
435
        }
436
 
437
        // clear screen up again
438
        clear();
439
 
440
        // update flags to paint display again if needed
441
        COSD_FLAGS &= ~COSD_ICONS_WRITTEN;
442
 
443
        // enable interrupts again
444
        sei();
445
}
446
 
329 cascade 447
#endif // ends !(ALLCHARSDEBUG|(WRITECHARS != -1))
321 cascade 448
/* ##########################################################################
449
 * MAIN
450
 * ##########################################################################*/
451
int main(void) {
339 cascade 452
    // set up FLAGS, compiler should flatten this one
453
    COSD_FLAGS = (NTSC << 0);
454
    COSD_FLAGS |= (HUD << 1);
455
    COSD_FLAGS |= (ARTHORIZON << 2);
456
        COSD_FLAGS |= (STATS << 3);
457
    COSD_FLAGS |= (WARNINGS << 4);
324 cascade 458
 
339 cascade 459
    // set up Atmega162 Ports
321 cascade 460
    DDRA |= (1 << PA1); // PA1 output (/CS)
461
    MAX_CS_HIGH
462
    DDRA |= (1 << PA2); // PA2 output (SDIN)
463
    MAX_SDIN_LOW
464
    DDRA |= (1 << PA3); // PA3 output (SCLK)
465
    MAX_SCLK_LOW
466
    DDRA |= (1 << PA5); // PA5 output (RESET)
467
    MAX_RESET_HIGH
468
 
469
    DDRC |= (1 << PC0); // PC0 output (LED1 gn)
470
    LED1_OFF
471
    DDRC |= (1 << PC1); // PC1 output (LED2 rt)
472
    LED2_OFF
473
    DDRC |= (1 << PC2); // PC2 output (LED3 gn)
474
    LED3_OFF
475
    DDRC |= (1 << PC3); // PC3 output (LED4 rt)
476
    LED4_OFF
477
 
478
    DDRC &= ~(1 << PC4); // PC4 input  (MODE)
479
    PORTC |= (1 << PC4); // pullup
480
    DDRC &= ~(1 << PC5); // PC5 input  (SET)
481
    PORTC |= (1 << PC5); // pullup
482
 
339 cascade 483
    // set up top and bottom lines
484
    if (COSD_FLAGS & COSD_FLAG_NTSC) {
485
        bottom_line = 12;
486
    } else {
487
        bottom_line = 14;
488
    }
326 cascade 489
 
339 cascade 490
    // reset the MAX7456 to be sure any undefined states do no harm
321 cascade 491
    MAX_RESET_LOW
492
    MAX_RESET_HIGH
493
 
494
    // give the FC/NC and the maxim time to come up
495
    LED4_ON
496
    _delay_ms(2000);
497
 
498
    LED4_OFF
499
 
331 cascade 500
 
339 cascade 501
    //Pushing NEW chars to the MAX7456
329 cascade 502
#if (WRITECHARS != -1)
339 cascade 503
    // DISABLE display (VM0)
321 cascade 504
    spi_send_byte(0x00, 0b00000000);
339 cascade 505
#include "characters.c"
321 cascade 506
 
331 cascade 507
#endif 
321 cascade 508
 
339 cascade 509
    // Setup Video Mode
510
    if (COSD_FLAGS & COSD_FLAG_NTSC) {
511
        // NTSC + enable display immediately (VM0)
512
        spi_send_byte(0x00, 0b00001000);
513
    } else {
514
        // PAL + enable display immediately (VM0)
515
        spi_send_byte(0x00, 0b01001000);
516
    }
321 cascade 517
 
518
    // clear all display-mem (DMM)
519
    spi_send_byte(0x04, 0b00000100);
520
 
521
    // clearing takes 12uS according to maxim so lets wait longer
522
    _delay_us(120);
523
 
524
    // 8bit mode
525
    spi_send_byte(0x04, 0b01000000);
526
 
527
    // write blank chars to whole screen
528
    clear();
529
 
329 cascade 530
#if !(ALLCHARSDEBUG|(WRITECHARS != -1))
321 cascade 531
    // init usart
532
    usart1_init();
533
 
534
    // set up timer
535
    TCCR0 |= (1 << CS00) | (1 << CS01); // timer0 prescaler 64
536
    OCR0 = 6; // preload
537
    TIMSK |= (1 << TOIE0); // enable overflow timer0
538
 
326 cascade 539
    // enable interrupts
321 cascade 540
    sei();
541
#endif
542
 
543
    //write_ascii_string(2,  7, "         CaScAdE          ");
544
    //write_ascii_string(2,  8, "is TESTING his open source");
545
    //write_ascii_string(2,  9, "    EPi OSD Firmware");
546
 
547
    // custom char preview
548
    /*write_char_xy( 2, 7, 200);
549
    write_char_xy( 3, 7, 201);
550
    write_char_xy( 4, 7, 202);
551
    write_char_xy( 5, 7, 203);
552
    write_char_xy( 6, 7, 204);
553
    write_char_xy( 7, 7, 205);
554
    write_char_xy( 8, 7, 206);
555
    write_char_xy( 9, 7, 207);
556
    write_char_xy(10, 7, 208);
557
    write_char_xy(11, 7, 209);
558
    write_char_xy(12, 7, 210);
559
    write_char_xy(13, 7, 211);
560
    write_char_xy(14, 7, 212);
561
    write_char_xy(15, 7, 213);
562
    write_char_xy(16, 7, 214);
563
    write_char_xy(17, 7, 215);*/
564
 
565
    // we are ready
566
    LED3_ON
567
 
568
 
569
 
329 cascade 570
#if ALLCHARSDEBUG | (WRITECHARS != -1)
321 cascade 571
        clear();
572
    write_all_chars();
573
#else
339 cascade 574
        // clear serial screen
575
        //usart1_puts("\x1B[2J\x1B[H");
576
        //usart1_puts("hello world!\r\n");
321 cascade 577
 
339 cascade 578
 
346 cascade 579
        // request data ever 100ms from FC;
580
        //usart1_request_mk_data(0, 'd', 100);
339 cascade 581
 
582
        // request OSD Data from NC every 100ms
346 cascade 583
        usart1_request_mk_data(1, 'o', 100);
584
 
339 cascade 585
    // and disable debug...
346 cascade 586
        //usart1_request_mk_data(0, 'd', 0);
321 cascade 587
 
339 cascade 588
    // disable TXD-pin
589
    usart1_DisableTXD();
331 cascade 590
 
339 cascade 591
    // stats for after flight
592
    int16_t max_Altimeter = 0;
593
    uint16_t max_GroundSpeed = 0;
594
    int16_t max_Distance = 0;
595
    uint8_t min_UBat = 255;
596
    uint16_t max_FlyingTime = 0;
321 cascade 597
 
339 cascade 598
    // flags from last round to check for changes
599
    uint8_t old_MKFlags = 0;
600
 
321 cascade 601
    char* directions[8] = {"NE", "E ", "SE", "S ", "SW", "W ", "NW", "N "};
377 cascade 602
    //char arrowdir[8] = {218, 217, 224, 223, 222, 221, 220, 219};
321 cascade 603
 
349 cascade 604
        /*write_ndigit_number_s_10th(5, 10, 1, 100, 0);
605
        write_ndigit_number_s_10th(5, 11, -1, 100, 0);
606
        write_ndigit_number_s_10th(5, 12, -11, 100, 0);*/
607
 
377 cascade 608
        //write_ndigit_number_u(2,2, heading_fine_conv(45), 100, 0);
609
 
321 cascade 610
    while (1) {
339 cascade 611
        // write icons at init or after menu/mode-switch
612
        if (!(COSD_FLAGS & COSD_ICONS_WRITTEN) && (COSD_FLAGS & COSD_FLAG_HUD)) {
613
            write_char_xy(5, top_line, 203); // km/h
614
            write_char_xy(10, top_line, 202); // RC-transmitter
615
            write_char_xy(16, top_line, 208); // degree symbol
616
            write_char_xy(27, top_line, 204); // small meters m
377 cascade 617
            //write_ascii_string(6, bottom_line, "V"); // voltage
339 cascade 618
            write_char_xy(14, bottom_line, 209); // on clock
619
            write_char_xy(22, bottom_line, 210); // fly clock
620
            write_char_xy(26, bottom_line, 200); // sat1
621
            write_char_xy(27, bottom_line, 201); // sat2
622
            COSD_FLAGS |= COSD_ICONS_WRITTEN;
623
        }
321 cascade 624
        if (rxd_buffer_locked) {
339 cascade 625
            if (COSD_FLAGS & COSD_FLAG_HUD) {
626
                if (rxd_buffer[2] == 'D') { // FC Data
627
                    /*Decode64();
628
                    debugData = *((DebugOut_t*) pRxData);
629
                    write_number_s(12, 2, RxDataLen);
630
                    write_number_s(20, 2, setsReceived++);
631
                    write_number_s(12, 3, debugData.Analog[0]); // AngleNick
632
                    write_number_s(12, 4, debugData.Analog[1]); // AngleRoll
336 cascade 633
                                        write_number_s(12, 5, debugData.Analog[5]); // Height
339 cascade 634
                    write_number_s(12, 6, debugData.Analog[9]); // Voltage
635
                    write_number_s(12, 7, debugData.Analog[10]);// RC Signal
336 cascade 636
                                        write_number_s(12, 8, debugData.Analog[11]);// Gyro compass*/
339 cascade 637
                } else if (rxd_buffer[2] == 'O') { // NC OSD Data
638
                    Decode64();
639
                    naviData = *((NaviData_t*) pRxData);
321 cascade 640
 
339 cascade 641
                    // first line
373 cascade 642
                    write_ndigit_number_u(2, top_line, (uint16_t) (((uint32_t) naviData.GroundSpeed * (uint32_t)9) / (uint32_t)250), 100, 0);
321 cascade 643
 
349 cascade 644
                    write_ndigit_number_u(7, top_line, naviData.RC_Quality, 100, 0);
339 cascade 645
                    if (naviData.RC_Quality <= RCLVL_WRN && last_RC_Quality > RCLVL_WRN) {
646
                        for (uint8_t x = 0; x < 4; x++)
647
                            write_char_att_xy(7 + x, top_line, BLINK);
648
                    } else if (naviData.RC_Quality > RCLVL_WRN && last_RC_Quality <= RCLVL_WRN) {
649
                        for (uint8_t x = 0; x < 4; x++)
650
                            write_char_att_xy(7 + x, top_line, 0);
651
                    }
652
                    last_RC_Quality = naviData.RC_Quality;
321 cascade 653
 
349 cascade 654
                    write_ndigit_number_u(13, top_line, naviData.CompassHeading, 100, 0);
321 cascade 655
 
339 cascade 656
                    write_ascii_string(17, top_line, directions[heading_conv(naviData.CompassHeading)]);
377 cascade 657
 
658
                                        draw_variometer(20, top_line, naviData.Variometer);
321 cascade 659
 
339 cascade 660
                    //note:lephisto:according to several sources it's /30
349 cascade 661
                    if (naviData.Altimeter > 300 || naviData.Altimeter < -300) {
339 cascade 662
                        // above 10m only write full meters
349 cascade 663
                        write_ndigit_number_s(23, top_line, naviData.Altimeter / 30, 1000, 0);
339 cascade 664
                    } else {
665
                        // up to 10m write meters.dm
349 cascade 666
                        //write_number_u_10th(21, top_line, naviData.Altimeter / 3);
667
                                                write_ndigit_number_s_10th(23, top_line, naviData.Altimeter / 3, 100, 0);
339 cascade 668
                    }
321 cascade 669
 
339 cascade 670
                    // seccond line
671
                    draw_compass(11, top_line + 1, naviData.CompassHeading);
321 cascade 672
 
339 cascade 673
                    // TODO: verify correctness
674
                    uint16_t heading_home = (naviData.HomePositionDeviation.Bearing + 360 - naviData.CompassHeading) % 360;
377 cascade 675
                    //write_char_xy(27, top_line + 1, arrowdir[heading_conv(heading_home)]);
676
                                        // finer resolution, 0xa0 is first character and we add the index 0 <= index < 16
677
                                        write_char_xy(27, top_line + 1, 0xa0 + heading_fine_conv(heading_home));
321 cascade 678
 
355 shaddi 679
                    write_ndigit_number_u(24, top_line + 1, naviData.HomePositionDeviation.Distance / 10, 100, 0);
321 cascade 680
 
339 cascade 681
                    // center
682
                    if (naviData.MKFlags & FLAG_MOTOR_RUN) { // should be engines running
683
                        if (!(old_MKFlags & FLAG_MOTOR_RUN)) { // motors just started, clear middle
684
                            clear();
685
                            // update flags to paint display again if needed
686
                            COSD_FLAGS &= ~COSD_ICONS_WRITTEN;
687
                        }
688
                        if (COSD_FLAGS & COSD_FLAG_ARTHORIZON) {
689
                            draw_artificial_horizon(top_line + 2, bottom_line - 1, naviData.AngleNick, naviData.AngleRoll);
690
                        }
691
                    } else {
336 cascade 692
                                                // stats
339 cascade 693
                                                if (COSD_FLAGS & COSD_FLAG_STATS) {
346 cascade 694
                                                        write_ascii_string_pgm(2, 5, stats_item_pointers[0]); // max Altitude
349 cascade 695
                                write_ndigit_number_s(18, 5, max_Altimeter / 30, 1000, 0);
339 cascade 696
                                write_char_xy(22, 5, 204); // small meters m
346 cascade 697
                                                        write_ascii_string_pgm(2, 6, stats_item_pointers[1]); // max Speed
349 cascade 698
                                write_ndigit_number_u(19, 6, (uint16_t) (((uint32_t) max_GroundSpeed * 36) / 1000), 100, 0);
339 cascade 699
                                write_char_xy(22, 6, 203); // km/h
346 cascade 700
                                                        write_ascii_string_pgm(2, 7, stats_item_pointers[2]); // max Distance
349 cascade 701
                                write_ndigit_number_u(19, 7, max_Distance / 100, 100, 0);
339 cascade 702
                                write_char_xy(22, 7, 204); // small meters m
346 cascade 703
                                                        write_ascii_string_pgm(2, 8, stats_item_pointers[3]); // min voltage
349 cascade 704
                                                        write_ndigit_number_u_10th(18, 8, min_UBat, 100, 0);
339 cascade 705
                                write_ascii_string(22, 8, "V"); // voltage
346 cascade 706
                                                        write_ascii_string_pgm(2, 9, stats_item_pointers[4]); // max time
339 cascade 707
                                write_time(16, 9, max_FlyingTime);
708
                                write_char_xy(22, 9, 210); // fly clock
709
                                                } else if (COSD_FLAGS & COSD_FLAG_ARTHORIZON) { // if no stats there is space horizon
710
                            draw_artificial_horizon(top_line + 2, bottom_line - 1, naviData.AngleNick, naviData.AngleRoll);
711
                        }
712
                    }
321 cascade 713
 
339 cascade 714
                    // bottom line
349 cascade 715
                                        write_ndigit_number_u_10th(2, bottom_line, naviData.UBat, 100, 0);
339 cascade 716
                    if (naviData.UBat <= UBAT_WRN && last_UBat > UBAT_WRN) {
717
                        for (uint8_t x = 0; x < 7; x++)
718
                            write_char_att_xy(x, bottom_line, BLINK);
719
                    } else {
720
                        for (uint8_t x = 0; x < 7; x++)
721
                            write_char_att_xy(x, bottom_line, 0);
722
                    }
377 cascade 723
                                        draw_battery(6, bottom_line, naviData.UBat);
321 cascade 724
 
339 cascade 725
                    write_time(8, bottom_line, uptime);
726
                    write_time(16, bottom_line, naviData.FlyingTime);
321 cascade 727
 
349 cascade 728
                    write_ndigit_number_u(24, bottom_line, naviData.SatsInUse, 10, 0);
321 cascade 729
 
339 cascade 730
                    if (naviData.NCFlags & NC_FLAG_CH) {
731
                        write_char_xy(27, bottom_line, 231); // gps ch
732
                    } else if (naviData.NCFlags & NC_FLAG_PH) {
733
                        write_char_xy(27, bottom_line, 230); // gps ph
734
                    } else { // (naviData.NCFlags & NC_FLAG_FREE)
735
                        write_char_xy(27, bottom_line, 201); // sat2 (free)
736
                    }
321 cascade 737
 
339 cascade 738
                    //write_number_s(8, 5, RxDataLen);
739
                    //write_number_s(16, 5, setsReceived++);
321 cascade 740
 
339 cascade 741
                    // remember statistics
742
                    if (naviData.Altimeter > max_Altimeter) max_Altimeter = naviData.Altimeter;
743
                    if (naviData.GroundSpeed > max_GroundSpeed) max_GroundSpeed = naviData.GroundSpeed;
744
                    if (naviData.HomePositionDeviation.Distance > max_Distance) {
745
                        max_Distance = naviData.HomePositionDeviation.Distance;
746
                    }
747
                    if (naviData.UBat < min_UBat) min_UBat = naviData.UBat;
748
                    if (naviData.FlyingTime > max_FlyingTime) max_FlyingTime = naviData.FlyingTime;
749
 
750
                    old_MKFlags = naviData.MKFlags;
751
                }
752
            }
753
            seconds_since_last_data = 0;
321 cascade 754
            rxd_buffer_locked = 0;
755
        }
756
        // handle keypress
326 cascade 757
        if (s1_pressed()) {
339 cascade 758
            config_menu();
321 cascade 759
        }
339 cascade 760
        if (seconds_since_last_data > 2) {
346 cascade 761
                        // request OSD Data from NC every 100ms
762
                        usart1_request_mk_data(1, 'o', 100);
763
                        seconds_since_last_data = 0;
339 cascade 764
        }
321 cascade 765
    }
766
#endif
767
    return 0;
768
}