Subversion Repositories Projects

Rev

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