Subversion Repositories Projects

Rev

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