Subversion Repositories Projects

Rev

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