Subversion Repositories Projects

Rev

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