Subversion Repositories Projects

Rev

Rev 325 | Rev 327 | 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>
31
 
32
/* TODO:
33
 * - verifiy correctness of values
324 cascade 34
 * - clean up code :)
321 cascade 35
 */
36
 
37
/* ##########################################################################
38
 * Debugging and general purpose definitions
39
 * ##########################################################################*/
40
#define ALLCHARSDEBUG 0         // set to 1 and flash firmware to see all chars
325 cascade 41
#define WRITECHARS 0            // set to 2XX and flash firmware to write new char
321 cascade 42
                                                        // enables the allchars as well to see results
43
#define NTSC 0                          // set to 1 for NTSC mode + lifts the bottom line
44
#define ARTHORIZON 0            // set to 1 to enable roll&nick artificial horizon
324 cascade 45
#define NOOSD 0                         // set to 1 to disable OSD completely
46
#define NOOSD_BUT_WRN 0         // set to 1 to disable OSD completely but show 
47
                                                        // battery and receive signal warnings
321 cascade 48
#define UBAT_WRN 94                     // voltage for blinking warning, like FC settings
49
#define RCLVL_WRN 100           // make the RC level blink if below this number
50
 
51
// ### read datasheet before changing stuff below this line :)
52
#define BLINK   0b01001111      // attribute byte for blinking chars
53
 
54
/* ##########################################################################
324 cascade 55
 * FLAGS usable during runtime
56
 * ##########################################################################*/
326 cascade 57
#define COSD_FLAG_NTSC                   1
58
#define COSD_FLAG_ARTHORIZON     2
59
#define COSD_FLAG_NOOSD                  4
60
#define COSD_FLAG_NOOSD_BUT_WRN  8
61
#define COSD_ICONS_WRITTEN              16
324 cascade 62
 
63
/* ##########################################################################
321 cascade 64
 * Software SPI to communicate with MAX7456
65
 * ##########################################################################*/
66
#define MAX_CS_HIGH             PORTA |=  (1 << PA1);
67
#define MAX_CS_LOW              PORTA &= ~(1 << PA1);
68
#define MAX_SDIN_HIGH           PORTA |=  (1 << PA2);
69
#define MAX_SDIN_LOW            PORTA &= ~(1 << PA2);
70
#define MAX_SCLK_HIGH           PORTA |=  (1 << PA3);
71
#define MAX_SCLK_LOW            PORTA &= ~(1 << PA3);
72
#define MAX_RESET_HIGH          PORTA |=  (1 << PA5);
73
#define MAX_RESET_LOW           PORTA &= ~(1 << PA5);
74
 
75
/* ##########################################################################
76
 * LED controll
77
 * ##########################################################################*/
78
#define LED1_ON                 PORTC |=  (1 << PC0);
79
#define LED1_OFF                PORTC &= ~(1 << PC0);
80
#define LED2_ON                 PORTC |=  (1 << PC1);
81
#define LED2_OFF                PORTC &= ~(1 << PC1);
82
#define LED3_ON                 PORTC |=  (1 << PC2);
83
#define LED3_OFF                PORTC &= ~(1 << PC2);
84
#define LED4_ON                 PORTC |=  (1 << PC3);
85
#define LED4_OFF                PORTC &= ~(1 << PC3);
86
 
87
/* ##########################################################################
88
 * switch controll
89
 * ##########################################################################*/
324 cascade 90
#define S1_PRESSED              !(PINC & (1<<PC5))
91
#define S2_PRESSED              !(PINC & (1<<PC4))
321 cascade 92
 
93
/* ##########################################################################
94
 * gain some fake arm compat :)
95
 * ##########################################################################*/
96
#define u8 uint8_t
97
#define s8 int8_t
98
#define u16 uint16_t
99
#define s16 int16_t
100
#define u32 uint32_t
101
#define s32 int32_t
102
 
103
#if !(ALLCHARSDEBUG|WRITECHARS)
104
/* ##########################################################################
105
 * MK data strucs & flags
106
 * ##########################################################################*/
107
#define NC_FLAG_FREE                    1
108
#define NC_FLAG_PH                      2
109
#define NC_FLAG_CH                      4
110
#define NC_FLAG_RANGE_LIMIT             8
111
#define NC_SERIAL_LINK_OK               16
112
#define NC_FLAG_TARGET_REACHED          32
113
 
114
#define FLAG_MOTOR_RUN  1
115
#define FLAG_FLY        2
116
#define FLAG_CALIBRATE  4
117
#define FLAG_START      8
118
 
119
/*
120
 * FC Debug Struct
121
 * portions taken and adapted from
122
 * http://svn.mikrokopter.de/mikrowebsvn/filedetails.php?repname=FlightCtrl&path=%2Ftags%2FV0.72p%2Fuart.h
123
 */
124
typedef struct {
125
    uint8_t Digital[2];
126
    uint16_t Analog[32]; // Debugvalues
127
} __attribute__((packed)) DebugOut_t;
128
 
129
/*
130
 * NaviCtrl OSD Structs
131
 * portions taken and adapted from
132
 * http://svn.mikrokopter.de/mikrowebsvn/filedetails.php?repname=NaviCtrl&path=%2Ftags%2FV0.14e%2Fuart1.h
133
 */
134
typedef struct {
135
    s32 Longitude; // in 1E-7 deg
136
    s32 Latitude; // in 1E-7 deg
137
    s32 Altitude; // in mm
138
    u8 Status; // validity of data
139
} __attribute__((packed)) GPS_Pos_t;
140
 
141
typedef struct {
142
    s16 Distance; // distance to target in cm
143
    s16 Bearing; // course to target in deg
144
} __attribute__((packed)) GPS_PosDev_t;
145
 
146
typedef struct {
147
    GPS_Pos_t CurrentPosition; // see ubx.h for details
148
    GPS_Pos_t TargetPosition;
149
    GPS_PosDev_t TargetPositionDeviation;
150
    GPS_Pos_t HomePosition;
151
    GPS_PosDev_t HomePositionDeviation;
152
    u8 WaypointIndex; // index of current waypoints running from 0 to WaypointNumber-1
153
    u8 WaypointNumber; // number of stored waypoints
154
    u8 SatsInUse; // no of satellites used for position solution
155
    s16 Altimeter; // hight according to air pressure
156
    s16 Variometer; // climb(+) and sink(-) rate
157
    u16 FlyingTime; // in seconds
158
    u8 UBat; // Battery Voltage in 0.1 Volts
159
    u16 GroundSpeed; // speed over ground in cm/s (2D)
160
    s16 Heading; // current flight direction in deg as angle to north
161
    s16 CompassHeading; // current compass value
162
    s8 AngleNick; // current Nick angle in 1°
163
    s8 AngleRoll; // current Rick angle in 1°
164
    u8 RC_Quality; // RC_Quality
165
    u8 MKFlags; // Flags from FC
166
    u8 NCFlags; // Flags from NC
167
    u8 Errorcode; // 0 --> okay
168
    u8 OperatingRadius; // current operation radius around the Home Position in m
169
    u8 Reserve[7]; // for future use
170
} __attribute__((packed)) NaviData_t;
171
 
172
 
173
/* ##########################################################################
174
 * global definitions and global vars
175
 * ##########################################################################*/
176
#define baud 57600
177
 
178
#define RXD_BUFFER_LEN          150
179
#define TXD_BUFFER_LEN          150
180
 
181
volatile uint8_t rxd_buffer_locked = 0;
182
volatile uint8_t rxd_buffer[RXD_BUFFER_LEN];
183
volatile uint8_t txd_buffer[TXD_BUFFER_LEN];
184
volatile uint8_t ReceivedBytes = 0;
185
volatile uint8_t *pRxData = 0;
186
volatile uint8_t RxDataLen = 0;
187
volatile uint16_t setsReceived = 0;
188
 
189
volatile NaviData_t naviData;
190
volatile DebugOut_t debugData;
191
 
192
// cache old vars for blinking attribute, checkup is faster than full
193
// attribute write each time
194
volatile uint8_t last_UBat = 255;
195
volatile uint8_t last_RC_Quality = 255;
196
 
197
// 16bit should be enough, normal LiPos don't last that long
198
volatile uint16_t uptime = 0;
199
volatile uint16_t timer = 0;
200
 
201
#endif // ends !(ALLCHARSDEBUG|WRITECHARS)
326 cascade 202
 
203
// general PAL|NTSC distingiusch stuff
204
uint8_t top_line = 1;
205
uint8_t bottom_line = 14;
206
 
207
// Flags
208
uint8_t COSD_FLAGS = 0;
209
 
321 cascade 210
/* ##########################################################################
326 cascade 211
 * debounce buttons
212
 * ##########################################################################*/
213
int s1_pressed() {
214
        if (S1_PRESSED) {
215
                _delay_ms(25);
216
                if (S1_PRESSED) return 1;
217
        }
218
        return 0;
219
}
220
 
221
int s2_pressed() {
222
        if (S2_PRESSED) {
223
                _delay_ms(25);
224
                if (S2_PRESSED) return 1;
225
        }
226
        return 0;
227
}
228
 
229
/* ##########################################################################
321 cascade 230
 * MAX7456 SPI & Display stuff
231
 * ##########################################################################*/
232
 
233
/**
234
 * Send a byte through SPI
235
 */
236
void spi_send(uint8_t byte) {
237
    for (int8_t i = 7; i >= 0; i--) {
238
        if (((byte >> i) & 1)) {
239
            MAX_SDIN_HIGH
240
        } else {
241
            MAX_SDIN_LOW
242
        }
243
        MAX_SCLK_HIGH
244
        MAX_SCLK_LOW
245
    }
246
}
247
 
248
/**
249
 *  Send <byte> to <address> of MAX7456
250
 */
251
void spi_send_byte(uint8_t address, uint8_t byte) {
252
    // start sending
253
    MAX_CS_LOW
254
 
255
    spi_send(address);
256
    spi_send(byte);
257
 
258
    // end sending
259
    MAX_CS_HIGH
260
}
261
 
262
/**
263
 *  write a <character> to <address> of MAX7456 display memory
264
 */
265
void write_char(uint16_t address, char character) {
266
    spi_send_byte(0x05, (address & 0xFF00) >> 8); // DMAH
267
    spi_send_byte(0x06, (address & 0x00FF)); // DMAL
268
    spi_send_byte(0x07, character); // DMDI
269
}
270
 
271
/**
272
 *  write a character <attribute> to <address> of MAX7456 display memory
273
 */
274
void write_char_att(uint16_t address, char attribute) {
275
    // the only important part is that the DMAH[1] is set
276
    // so we add 2 which binary is the 2nd lowest byte
277
    spi_send_byte(0x05, ((address & 0xFF00) >> 8) | 2); // DMAH
278
    spi_send_byte(0x06, (address & 0x00FF)); // DMAL
279
    spi_send_byte(0x07, attribute); // DMDI
280
}
281
 
282
/**
283
 *  write a <character> at <x>/<y> to MAX7456 display memory
284
 */
285
void write_char_xy(uint8_t x, uint8_t y, char character) {
286
    uint16_t address = y * 30 + x;
287
    write_char(address, character);
288
}
289
 
290
/**
291
 *  write a  character <attribute> at <x>/<y> to MAX7456 display memory
292
 */
293
void write_char_att_xy(uint8_t x, uint8_t y, char attribute) {
294
    uint16_t address = y * 30 + x;
295
    write_char_att(address, attribute);
296
}
297
 
298
/**
299
 *  clear display by writing blank characters all over it
300
 */
301
void clear(void) {
302
    uint16_t memory_address = 0;
303
    for (unsigned int a = 0; a < 480; a++) {
304
        write_char(memory_address++, 0);
305
    }
306
}
307
 
308
/**
309
 *  write an ascii <character> to <address> of MAX7456 display memory
310
 */
311
void write_ascii_char(uint16_t address, char c) {
312
    if (c == 32) c = 0; // remap space
313
    else if (c > 48 && c <= 57) c -= 48; // remap numbers
314
    else if (c == '0') c = 10; // remap zero
315
    else if (c >= 65 && c <= 90) c -= 54; // remap big letters
316
    else if (c >= 97 && c <= 122) c -= 60; // remap small letters
317
    else if (c == '(') c = 63; // remap
318
    else if (c == ')') c = 64; // remap
319
    else if (c == '.') c = 65; // remap
320
    else if (c == '?') c = 66; // remap
321
    else if (c == ';') c = 67; // remap
322
    else if (c == ':') c = 68; // remap
323
    else if (c == ',') c = 69; // remap
324
    else if (c == '\'') c = 70; // remap
325
    else if (c == '/') c = 71; // remap
326
    else if (c == '"') c = 72; // remap
327
    else if (c == '-') c = 73; // remap minus
328
    else if (c == '<') c = 74; // remap
329
    else if (c == '>') c = 75; // remap
330
    else if (c == '@') c = 76; // remap
331
    write_char(address, c);
332
}
333
 
334
/**
335
 *  write an ascii <string> at <x>/<y> to MAX7456 display memory
336
 */
337
void write_ascii_string(uint8_t x, uint8_t y, char *string) {
338
    while (*string) {
339
        write_ascii_char(((x++)+(y * 30)), *string);
340
        string++;
341
    }
342
}
343
 
344
/**
345
 *  Write only the last three digits of a <number> at <x>/<y> to MAX7456
346
 *  display memory. takes full 16bit numbers as well for stuff
347
 *  like compass only taking three characters (values <= 999)
348
 */
349
void write_3digit_number_u(uint8_t x, uint8_t y, uint16_t number) {
350
    uint16_t num = 100;
351
    uint8_t started = 0;
352
 
353
    while (num > 0) {
354
        uint8_t b = number / num;
355
        if (b > 0 || started || num == 1) {
356
            write_ascii_char((x++)+(y * 30), '0' + b);
357
            started = 1;
358
        } else {
359
            write_ascii_char((x++)+(y * 30), 0);
360
        }
361
        number -= b * num;
362
 
363
        num /= 10;
364
    }
365
}
366
 
367
/**
368
 *  Write only the last two digits of a number at <x>/<y> to MAX7456
369
 *  display memory. takes full 16bit numbers as well for stuff
370
 *  like seconds only taking two characters (values <= 99)
371
 *  Since this is used for seconds only and it looks better, there
372
 *  is a trading 0 attached
373
 */
374
void write_2digit_number_u(uint8_t x, uint8_t y, uint16_t number) {
375
    uint16_t num = 10;
376
    uint8_t started = 0;
377
 
378
    while (num > 0) {
379
        uint8_t b = number / num;
380
        if (b > 0 || started || num == 1) {
381
            write_ascii_char((x++)+(y * 30), '0' + b);
382
            started = 1;
383
        } else {
384
            write_ascii_char((x++)+(y * 30), '0');
385
        }
386
        number -= b * num;
387
 
388
        num /= 10;
389
    }
390
}
391
 
392
/**
393
 *  write a unsigned number as /10th at <x>/<y> to MAX7456 display memory
394
 */
395
void write_number_u_10th(uint8_t x, uint8_t y, uint16_t number) {
396
    uint16_t num = 10000;
397
    uint8_t started = 0;
398
 
399
    while (num > 0) {
400
        uint8_t b = number / num;
401
 
402
        if (b > 0 || started || num == 1) {
403
            if ((num / 10) == 0) write_char((x++)+(y * 30), 65);
404
            write_ascii_char((x++)+(y * 30), '0' + b);
405
            started = 1;
406
        } else {
407
            write_ascii_char((x++)+(y * 30), 0);
408
        }
409
        number -= b * num;
410
 
411
        num /= 10;
412
    }
413
}
414
 
415
/**
416
 *  write a unsigned number at <x>/<y> to MAX7456 display memory
417
 */
418
void write_number_u(uint8_t x, uint8_t y, uint16_t number) {
419
    uint16_t num = 10000;
420
    uint8_t started = 0;
421
 
422
    while (num > 0) {
423
        uint8_t b = number / num;
424
        if (b > 0 || started || num == 1) {
425
            write_ascii_char((x++)+(y * 30), '0' + b);
426
            started = 1;
427
        } else {
428
            write_ascii_char((x++)+(y * 30), 0);
429
        }
430
        number -= b * num;
431
 
432
        num /= 10;
433
    }
434
}
435
 
436
/**
437
 *  write a signed number at <x>/<y> to MAX7456 display memory
438
 */
439
void write_number_s(uint8_t x, uint8_t y, int16_t w) {
440
    if (((uint16_t) w) > 32767) {
441
        w = w - 65536;
442
 
443
        int16_t num = -10000;
444
        uint8_t started = 0;
445
 
446
        while (num < 0) {
447
            uint8_t b = w / num;
448
            if (b > 0 || started || num == 1) {
449
                if (!started) write_char((x - 1)+(y * 30), 0x49);
450
                write_ascii_char((x++)+(y * 30), '0' + b);
451
                started = 1;
452
            } else {
453
                write_ascii_char((x++)+(y * 30), 0);
454
            }
455
            w -= b * num;
456
 
457
            num /= 10;
458
        }
459
    } else {
460
        write_char((x)+(y * 30), 0);
461
        write_number_u(x, y, w);
462
    }
463
}
464
 
465
/**
466
 *  write <seconds> as human readable time at <x>/<y> to MAX7456 display mem
467
 */
468
void write_time(uint8_t x, uint8_t y, uint16_t seconds) {
469
    uint16_t min = seconds / 60;
470
    seconds -= min * 60;
471
    write_3digit_number_u(x, y, min);
472
    write_char_xy(x + 3, y, 68);
473
    write_2digit_number_u(x + 4, y, seconds);
474
}
475
 
476
/**
477
 * for testing write all chars to screen
478
 */
479
void write_all_chars() {
480
    uint16_t x = 3, y = 2, t = 0;
481
    while (t < 256) {
482
        write_char_xy(x++, y, t++);
483
        if (x > 25) {
484
            y++;
485
            x = 3;
486
        }
487
    }
488
}
489
 
490
#if !(ALLCHARSDEBUG|WRITECHARS)
491
/* ##########################################################################
492
 * USART stuff
493
 * ##########################################################################*/
494
 
495
/**
496
 * init usart1
497
 */
498
void usart1_init() {
499
    UBRR1H = ((F_CPU / (16UL * baud)) - 1) >> 8;
500
    UBRR1L = (F_CPU / (16UL * baud)) - 1;
501
 
502
    // Enable receiver and transmitter; enable RX interrupt
503
    UCSR1B = (1 << RXEN1) | (1 << TXEN1) | (1 << RXCIE1);
504
 
505
    //asynchronous 8N1
506
    UCSR1C = (1 << URSEL1) | (3 << UCSZ10);
507
}
508
 
509
/**
510
 * send a single <character> through usart1
511
 */
512
void usart1_putc(unsigned char character) {
513
    // wait until UDR ready
514
    while (!(UCSR1A & (1 << UDRE1)));
515
    UDR1 = character;
516
}
517
 
518
/**
519
 * send a <string> throught usart1
520
 */
521
void usart1_puts(char *s) {
522
    while (*s) {
523
        usart1_putc(*s);
524
        s++;
525
    }
526
}
527
 
528
/**
529
 * receive data through usart1
530
 * portions taken and adapted from
531
 * http://svn.mikrokopter.de/mikrowebsvn/filedetails.php?repname=FlightCtrl&path=%2Fbranches%2FV0.72p+Code+Redesign+killagreg%2Fuart0.c
532
 */
533
ISR(SIG_USART1_RECV) {
534
    if (rxd_buffer_locked) return; // if rxd buffer is locked immediately return
535
    LED1_ON
536
            static uint16_t crc;
537
    static uint8_t ptr_rxd_buffer = 0;
538
    uint8_t crc1, crc2;
539
    uint8_t c;
540
 
541
    c = UDR1; // catch the received byte
542
 
543
    // the rxd buffer is unlocked
544
    if ((ptr_rxd_buffer == 0) && (c == '#')) // if rxd buffer is empty and syncronisation character is received
545
    {
546
                /*
547
                // skip other datasets
548
        if (ptr_rxd_buffer == 2 && rxd_buffer[ptr_rxd_buffer] != 'O') {
549
                        ptr_rxd_buffer = 0; // reset rxd buffer
550
                rxd_buffer_locked = 0; // unlock rxd buffer
551
                }*/
552
                rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer
553
        crc = c; // init crc
554
    } else if (ptr_rxd_buffer < RXD_BUFFER_LEN) // collect incomming bytes
555
    {
556
        if (c != '\r') // no termination character
557
        {
558
            rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
559
            crc += c; // update crc
560
        } else // termination character was received
561
        {
562
            // the last 2 bytes are no subject for checksum calculation
563
            // they are the checksum itself
564
            crc -= rxd_buffer[ptr_rxd_buffer - 2];
565
            crc -= rxd_buffer[ptr_rxd_buffer - 1];
566
            // calculate checksum from transmitted data
567
            crc %= 4096;
568
            crc1 = '=' + crc / 64;
569
            crc2 = '=' + crc % 64;
570
            // compare checksum to transmitted checksum bytes
571
            if ((crc1 == rxd_buffer[ptr_rxd_buffer - 2]) && (crc2 == rxd_buffer[ptr_rxd_buffer - 1])) { // checksum valid
572
                rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character
573
                ReceivedBytes = ptr_rxd_buffer + 1; // store number of received bytes
574
                rxd_buffer_locked = 1; // lock the rxd buffer
575
            } else { // checksum invalid
576
                rxd_buffer_locked = 0; // unlock rxd buffer
577
            }
578
            ptr_rxd_buffer = 0; // reset rxd buffer pointer
579
        }
580
    } else // rxd buffer overrun
581
    {
582
        ptr_rxd_buffer = 0; // reset rxd buffer
583
        rxd_buffer_locked = 0; // unlock rxd buffer
584
    }
585
    LED1_OFF
586
}
587
 
588
/**
589
 * Decode the recevied Buffer
590
 * portions taken and adapted from
591
 * http://svn.mikrokopter.de/mikrowebsvn/filedetails.php?repname=FlightCtrl&path=%2Ftags%2FV0.72p%2Fuart.c
592
 */
593
void Decode64(void) {
594
    uint8_t a, b, c, d;
595
    uint8_t x, y, z;
596
    uint8_t ptrIn = 3;
597
    uint8_t ptrOut = 3;
598
    uint8_t len = ReceivedBytes - 6;
599
 
600
    while (len) {
601
        a = rxd_buffer[ptrIn++] - '=';
602
        b = rxd_buffer[ptrIn++] - '=';
603
        c = rxd_buffer[ptrIn++] - '=';
604
        d = rxd_buffer[ptrIn++] - '=';
605
 
606
        x = (a << 2) | (b >> 4);
607
        y = ((b & 0x0f) << 4) | (c >> 2);
608
        z = ((c & 0x03) << 6) | d;
609
 
610
        if (len--) rxd_buffer[ptrOut++] = x;
611
        else break;
612
        if (len--) rxd_buffer[ptrOut++] = y;
613
        else break;
614
        if (len--) rxd_buffer[ptrOut++] = z;
615
        else break;
616
    }
617
    pRxData = &rxd_buffer[3];
618
    RxDataLen = ptrOut - 3;
619
}
620
 
621
/**
622
 * request Data through USART in special MK format by adding checksum and
623
 * encode data in modified Base64
624
 * portions taken and adapted from
625
 * http://svn.mikrokopter.de/mikrowebsvn/filedetails.php?repname=FlightCtrl&path=%2Ftags%2FV0.72p%2Fuart.c
626
 */
627
void sendMKData(unsigned char cmd, unsigned char addr, unsigned char *snd, unsigned char len) {
628
    unsigned int pt = 0;
629
    unsigned char a, b, c;
630
    unsigned char ptr = 0;
631
 
632
    txd_buffer[pt++] = '#'; // Start-Byte
633
    txd_buffer[pt++] = 'a' + addr; // Adress
634
    txd_buffer[pt++] = cmd; // Command
635
    while (len) {
636
        if (len) {
637
            a = snd[ptr++];
638
            len--;
639
        } else a = 0;
640
        if (len) {
641
            b = snd[ptr++];
642
            len--;
643
        } else b = 0;
644
        if (len) {
645
            c = snd[ptr++];
646
            len--;
647
        } else c = 0;
648
        txd_buffer[pt++] = '=' + (a >> 2);
649
        txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4));
650
        txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6));
651
        txd_buffer[pt++] = '=' + (c & 0x3f);
652
    }
653
 
654
    // add crc
655
    unsigned int tmpCRC = 0, i;
656
    for (i = 0; i < pt; i++) {
657
        tmpCRC += txd_buffer[i];
658
    }
659
    tmpCRC %= 4096;
660
    txd_buffer[i++] = '=' + tmpCRC / 64;
661
    txd_buffer[i++] = '=' + tmpCRC % 64;
662
    txd_buffer[i++] = '\r';
663
 
664
    usart1_puts((char*) txd_buffer);
665
}
666
 
667
/* ##########################################################################
668
 * timer stuff
669
 * ##########################################################################*/
670
 
671
/*
672
 * timer kicks in every 1000uS
673
 */
674
ISR(TIMER0_OVF_vect) {
675
    OCR0 = 6; // preload
676
    if (!timer--) {
677
        uptime++;
678
        timer = 999;
679
    }
680
}
681
 
682
/* ##########################################################################
683
 * compass stuff
684
 * ##########################################################################*/
685
 
686
/**
687
 * convert the <heading> gotton from NC into an index
688
 */
689
uint8_t heading_conv(uint16_t heading) {
690
    if (heading > 23 && heading < 68) {
691
        //direction = "NE";
692
        return 0;
693
    } else if (heading > 67 && heading < 113) {
694
        //direction = "E ";
695
        return 1;
696
    } else if (heading > 112 && heading < 158) {
697
        //direction = "SE";
698
        return 2;
699
    } else if (heading > 157 && heading < 203) {
700
        //direction = "S ";
701
        return 3;
702
    } else if (heading > 202 && heading < 248) {
703
        //direction = "SW";
704
        return 4;
705
    } else if (heading > 247 && heading < 293) {
706
        //direction = "W ";
707
        return 5;
708
    } else if (heading > 292 && heading < 338) {
709
        //direction = "NW";
710
        return 6;
711
    }
712
    //direction = "N ";
713
    return 7;
714
}
715
 
716
/**
717
 * draw a compass rose at <x>/<y> for <heading>
718
 */
719
void draw_compass(uint8_t x, uint8_t y, uint16_t heading) {
720
    //char* rose = "---N---O---S---W---N---O---S---W---N---O---S---W";
721
    char rose[48] = {216, 215, 216, 211, 216, 215, 216, 213, 216, 215, 216, 212,
722
                    216, 215, 216, 214, 216, 215, 216, 211, 216, 215, 216, 213,
723
                    216, 215, 216, 212, 216, 215, 216, 214, 216, 215, 216, 211,
724
                    216, 215, 216, 213, 216, 215, 216, 212, 216, 215, 216, 214};
725
        // the center is char 19 (north), we add the current heading in 8th
726
        // which would be 22.5 degrees, but float would bloat up the code
727
        // and *10 / 225 would take ages... so we take the uncorrect way
728
    uint8_t front = 19 + (heading / 22);
729
    for (uint8_t i = 0; i < 9; i++) {
730
                write_char_xy(x++, y, rose[front - 4 + i]);
731
    }
732
}
733
 
734
/* ##########################################################################
735
 * artificial horizon
736
 * ##########################################################################*/
737
// remember last time displayed values
738
int8_t old_af_x = -1, old_af_y = -1;
739
 
740
/**
741
 * draw roll und nick indicators (could be enhanced to full artificial horizon)
742
 * from line <firstline> to <listlines> for given <nick> and <roll> values
743
 */
744
void draw_artificial_horizon(uint8_t firstline, uint8_t lastline, int16_t nick, int16_t roll) {
745
        char noodle[5] = {225, 225, 226, 227, 227};
746
        uint8_t center_x = 15;
747
        uint8_t center_y = lastline - firstline;
748
        center_y = 7;
749
        write_char_xy(center_x,center_y,228);
750
        uint8_t cpos, nicky, rollx;
751
 
752
        // which line
753
        int8_t ypos =  nick / 20;
754
        // which character from the array?
755
        if (nick < 0) {
756
                cpos = -1*((nick - (ypos * 20))/4);
757
                ypos--;
758
        } else cpos = 4-((nick - (ypos * 20))/4);
759
        if (cpos > 4) cpos = 4;
760
 
761
        nicky = center_y - ypos;
762
        if (nicky > lastline) nicky = lastline;
763
        else if (nicky < firstline) nicky = firstline;
764
 
765
        // ensure roll-borders
766
        rollx = (roll / 8)+15;
767
        if (rollx < 2) rollx = 2;
768
        else if (rollx > 28) rollx = 28;
769
 
770
 
771
        // clear roll
772
        if (old_af_x != rollx && old_af_x >= 0) {
773
                write_char_xy(old_af_x,13,0);
774
        }
775
 
776
        // clear nick
777
        if (old_af_y != nicky && old_af_y >= 0) {
778
                write_char_xy(center_x-1,old_af_y,0);
779
                write_char_xy(center_x+1,old_af_y,0);
780
        }
781
 
782
 
783
        // draw nick
784
        write_char_xy(center_x-1,nicky,noodle[cpos]);
785
        write_char_xy(center_x+1,nicky,noodle[cpos]);
786
 
787
        // draw roll
788
        write_char_xy(rollx,lastline,229);
789
 
790
        // update old vars
791
        old_af_x = rollx;
792
        old_af_y = nicky;
793
 
794
        // debug numbers
795
        //write_3digit_number_u(20,6,cpos);
796
        //write_number_s(20,7,ypos);    
797
        //write_number_s(0,7,nick);             
798
        //write_number_s(18,11,roll);   
799
}
800
 
326 cascade 801
/* ##########################################################################
802
 * A simple config menu for the flags
803
 * ##########################################################################*/
804
void config_menu(void) {
805
        // disable interrupts (makes the menu more smoothely)
806
        cli();
321 cascade 807
 
326 cascade 808
        // clear screen
809
        clear();
810
 
811
        char* menu[4] = {"Normal OSD      ",
812
                                         "+ Art.Horizon   ",
813
                                         "NO OSD          ",
814
                                         "NO OSD but WRN  "};
815
 
816
        uint8_t inmenu = 1;
817
        uint8_t chosen = 0;
818
        write_ascii_string(10,  4, "Config Menu");
819
 
820
        // clear all mode flags
821
        COSD_FLAGS &= ~(COSD_FLAG_ARTHORIZON | COSD_FLAG_NOOSD | COSD_FLAG_NOOSD_BUT_WRN);
822
 
823
        // wait a bit before doing stuff so user has chance to release button
824
        _delay_ms(250);
825
 
826
        while (inmenu) {
827
                        write_ascii_string(2,  7, menu[chosen]);
828
                        if (s2_pressed()) {
829
                                chosen = (chosen + 1) % 4;
830
                                _delay_ms(500);
831
                        } else if (s1_pressed()) {
832
                                switch (chosen) {
833
                                        case 1:         // artificial horizon
834
                                                COSD_FLAGS |= COSD_FLAG_ARTHORIZON;
835
                                                break;
836
                                        case 2:         // everything off
837
                                                COSD_FLAGS |= COSD_FLAG_NOOSD;
838
                                                break;
839
                                        case 3:         // only warning
840
                                                COSD_FLAGS |= COSD_FLAG_NOOSD_BUT_WRN;
841
                                                break;
842
                                        //default:      // normal OSD, so let the flags cleared
843
                                }
844
                                // leave menu
845
                                inmenu = 0;
846
                                _delay_ms(500);
847
                        }
848
        }
849
 
850
        // clear screen up again
851
        clear();
852
 
853
        // update flags to paint display again if needed
854
        COSD_FLAGS &= ~COSD_ICONS_WRITTEN;
855
 
856
        // enable interrupts again
857
        sei();
858
}
859
 
860
#endif // ends !(ALLCHARSDEBUG|WRITECHARS)
861
 
321 cascade 862
/* ##########################################################################
863
 * MAIN
864
 * ##########################################################################*/
865
int main(void) {
324 cascade 866
        // set up FLAGS, compiler should flatten this one
326 cascade 867
        COSD_FLAGS = (NTSC << (COSD_FLAG_NTSC - 1));
324 cascade 868
        COSD_FLAGS |= (ARTHORIZON << (COSD_FLAG_ARTHORIZON - 1));
869
        COSD_FLAGS |= (NOOSD << (COSD_FLAG_NOOSD - 1));
870
        COSD_FLAGS |= (NOOSD_BUT_WRN << (COSD_FLAG_NOOSD_BUT_WRN - 1));
871
 
872
        // set up Atmega162 Ports
321 cascade 873
    DDRA |= (1 << PA1); // PA1 output (/CS)
874
    MAX_CS_HIGH
875
    DDRA |= (1 << PA2); // PA2 output (SDIN)
876
    MAX_SDIN_LOW
877
    DDRA |= (1 << PA3); // PA3 output (SCLK)
878
    MAX_SCLK_LOW
879
    DDRA |= (1 << PA5); // PA5 output (RESET)
880
    MAX_RESET_HIGH
881
 
882
    DDRC |= (1 << PC0); // PC0 output (LED1 gn)
883
    LED1_OFF
884
    DDRC |= (1 << PC1); // PC1 output (LED2 rt)
885
    LED2_OFF
886
    DDRC |= (1 << PC2); // PC2 output (LED3 gn)
887
    LED3_OFF
888
    DDRC |= (1 << PC3); // PC3 output (LED4 rt)
889
    LED4_OFF
890
 
891
    DDRC &= ~(1 << PC4); // PC4 input  (MODE)
892
    PORTC |= (1 << PC4); // pullup
893
    DDRC &= ~(1 << PC5); // PC5 input  (SET)
894
    PORTC |= (1 << PC5); // pullup
895
 
326 cascade 896
        // set up top and bottom lines
897
        if (COSD_FLAGS & COSD_FLAG_NTSC) {
898
                bottom_line = 12;
899
        } else {
900
                bottom_line = 14;
901
        }
902
 
903
        // reset the MAX7456 to be sure any undefined states do no harm
321 cascade 904
    MAX_RESET_LOW
905
    MAX_RESET_HIGH
906
 
324 cascade 907
        // check for keypress at startup
326 cascade 908
        if (s2_pressed()) { // togle COSD_FLAG_ARTHORIZON
324 cascade 909
                        COSD_FLAGS ^= (1 << (COSD_FLAG_ARTHORIZON - 1));
910
                        _delay_ms(100);
911
    }
912
 
321 cascade 913
    // give the FC/NC and the maxim time to come up
914
    LED4_ON
915
    _delay_ms(2000);
916
 
917
    LED4_OFF
918
 
919
    /* ##########################################################################
920
     * Pushing NEW chars to the MAX7456
921
     * ##########################################################################*/
922
#if WRITECHARS
923
        void learn_char(uint8_t number, unsigned char* data) {
924
        // select character to write (CMAH)
925
        spi_send_byte(0x09, number);
926
 
927
        for (uint8_t i = 0; i < 54; i++) {
928
            // select 4pixel byte of char (CMAL)
929
            spi_send_byte(0x0A, i);
930
 
931
            // write 4pixel byte of char (CMDI)
932
            spi_send_byte(0x0B, data[i]);
933
        }
934
 
935
        // write to the NVM array from the shadow RAM (CMM)
936
        spi_send_byte(0x08, 0b10100000);
937
 
938
        // according to maxim writing to nvram takes about 12ms, lets wait longer
939
        _delay_ms(120);
940
    }
941
 
942
    // DISABLE display (VM0)
943
    spi_send_byte(0x00, 0b00000000);
944
 
945
    /**
946
     * easy char creation:
947
     * http://cascade.dyndns.org/~cascade/scripts/max7456/
948
     */
326 cascade 949
        // flashing more than 8 chars per time is not proven to be safe
950
        // so take care
951
#if WRITECHARS == 200
952
        // GPS
321 cascade 953
    unsigned char cc8[54] = {0x55, 0x50, 0x55, 0x55, 0x4a, 0x15, 0x55, 0x2a,
954
        0x85, 0x55, 0x2a, 0xa1, 0x55, 0x4a, 0xa8, 0x55,
955
        0x52, 0xa8, 0x55, 0x54, 0xaa, 0x55, 0x55, 0x09,
956
        0x55, 0x55, 0x52, 0x55, 0x55, 0x1a, 0x55, 0x51,
957
        0x96, 0x55, 0x18, 0x85, 0x54, 0x88, 0x28, 0x54,
958
        0x82, 0x05, 0x55, 0x20, 0xa1, 0x55, 0x48, 0x15,
959
        0x55, 0x52, 0x85, 0x55, 0x54, 0x15};
960
 
961
    unsigned char cc9[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
962
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x45,
963
        0x55, 0x55, 0x21, 0x55, 0x55, 0xa8, 0x55, 0x55,
964
        0xa1, 0x55, 0x55, 0x98, 0x15, 0x55, 0x2a, 0x85,
965
        0x55, 0x4a, 0xa1, 0x55, 0x4a, 0xa8, 0x55, 0x52,
966
        0xaa, 0x15, 0x54, 0xaa, 0x15, 0x55, 0x28, 0x55,
967
        0x55, 0x41, 0x55, 0x55, 0x55, 0x55};
968
 
969
    // RC
970
    unsigned char cca[54] = {0x54, 0xaa, 0x85, 0x52, 0x00, 0x21, 0x48, 0x2a,
971
        0x08, 0x60, 0x80, 0x82, 0x62, 0x08, 0x22, 0x62,
972
        0x2a, 0x22, 0x62, 0x08, 0x22, 0x60, 0x88, 0x82,
973
        0x48, 0x08, 0x08, 0x52, 0x08, 0x21, 0x54, 0x48,
974
        0x45, 0x55, 0x48, 0x55, 0x55, 0x48, 0x55, 0x55,
975
        0x48, 0x55, 0x55, 0x48, 0x55, 0x55, 0x48, 0x55,
976
        0x55, 0x2a, 0x15, 0x54, 0xaa, 0x85};
977
 
978
    // km/h
979
    unsigned char ccb[54] = {0x55, 0x55, 0x55, 0x01, 0x55, 0x55, 0x21, 0x55,
980
        0x55, 0x20, 0x15, 0x55, 0x22, 0x15, 0x55, 0x28,
981
        0x15, 0x55, 0x22, 0x15, 0x55, 0x00, 0x00, 0x15,
982
        0x52, 0xaa, 0x15, 0x52, 0x22, 0x15, 0x52, 0x22,
983
        0x15, 0x50, 0x00, 0x05, 0x55, 0x54, 0x85, 0x55,
984
        0x54, 0x80, 0x55, 0x54, 0xa8, 0x55, 0x54, 0x88,
985
        0x55, 0x54, 0x88, 0x55, 0x54, 0x00};
986
 
987
 
988
    // small meters m
989
    unsigned char ccc[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
990
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
991
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
992
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
993
        0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x15, 0x22,
994
        0x8a, 0x15, 0x28, 0xa2, 0x15, 0x20, 0x82, 0x15,
995
        0x20, 0x82, 0x15, 0x00, 0x00, 0x15};
996
 
997
    // vario down
998
    unsigned char ccd[54] = {0x55, 0x00, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28,
999
        0x55, 0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x55,
1000
        0x28, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28, 0x55,
1001
        0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28,
1002
        0x55, 0x00, 0x28, 0x00, 0x2a, 0xaa, 0xa8, 0x0a,
1003
        0xaa, 0xa0, 0x42, 0xaa, 0x81, 0x50, 0xaa, 0x05,
1004
        0x54, 0x28, 0x15, 0x55, 0x00, 0x55};
1005
 
1006
    // vario hold
1007
    unsigned char cce[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1008
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1009
        0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00,
1010
        0x2a, 0xaa, 0xa8, 0x2a, 0xaa, 0xa8, 0x00, 0x00,
1011
        0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1012
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1013
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1014
 
1015
    // vario up
1016
    unsigned char ccf[54] = {0x55, 0x00, 0x55, 0x54, 0x28, 0x15, 0x50, 0xaa,
1017
        0x05, 0x42, 0xaa, 0x81, 0x0a, 0xaa, 0xa0, 0x2a,
1018
        0xaa, 0xa8, 0x00, 0x28, 0x00, 0x55, 0x28, 0x55,
1019
        0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28,
1020
        0x55, 0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x55,
1021
        0x28, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28, 0x55,
1022
        0x55, 0x28, 0x55, 0x55, 0x00, 0x55};
1023
 
326 cascade 1024
    learn_char(200, cc8);
1025
    learn_char(201, cc9);
1026
    learn_char(202, cca);
1027
    learn_char(203, ccb);
1028
    learn_char(204, ccc);
1029
    learn_char(205, ccd);
1030
    learn_char(206, cce);
1031
    learn_char(207, ccf);
1032
#endif
1033
#if WRITECHARS == 208
1034
   // degree symbol
321 cascade 1035
    unsigned char cd0[54] = {0x55, 0x55, 0x55, 0x54, 0x01, 0x55, 0x52, 0xa8,
1036
        0x55, 0x48, 0x02, 0x15, 0x48, 0x52, 0x15, 0x48,
1037
        0x52, 0x15, 0x48, 0x02, 0x15, 0x52, 0xa8, 0x55,
1038
        0x54, 0x01, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1039
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1040
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1041
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1042
 
1043
    // clock on symbol
1044
    unsigned char cd1[54] = {0x54, 0x14, 0x51, 0x52, 0x82, 0x08, 0x48, 0x22,
1045
        0x88, 0x48, 0x22, 0x28, 0x48, 0x22, 0x28, 0x52,
1046
        0x82, 0x08, 0x54, 0x14, 0x51, 0x55, 0x40, 0x55,
1047
        0x55, 0x2a, 0x15, 0x54, 0x88, 0x85, 0x52, 0x08,
1048
        0x21, 0x48, 0x48, 0x08, 0x48, 0x4a, 0x88, 0x48,
1049
        0x50, 0x08, 0x52, 0x15, 0x21, 0x54, 0x80, 0x85,
1050
        0x55, 0x2a, 0x15, 0x55, 0x40, 0x55};
1051
 
1052
    // clock fly symbol
1053
    unsigned char cd2[54] = {0x40, 0x45, 0x11, 0x2a, 0x20, 0x88, 0x20, 0x20,
1054
        0x88, 0x28, 0x21, 0x21, 0x21, 0x20, 0x21, 0x21,
1055
        0x2a, 0x21, 0x45, 0x40, 0x45, 0x55, 0x40, 0x55,
1056
        0x55, 0x2a, 0x15, 0x54, 0x88, 0x85, 0x52, 0x08,
1057
        0x21, 0x48, 0x48, 0x08, 0x48, 0x4a, 0x88, 0x48,
1058
        0x50, 0x08, 0x52, 0x15, 0x21, 0x54, 0x80, 0x85,
1059
        0x55, 0x2a, 0x15, 0x55, 0x40, 0x55};
1060
 
1061
    // compass north
1062
    unsigned char cd3[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1063
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54,
1064
        0x54, 0x55, 0x52, 0x12, 0x15, 0x52, 0x82, 0x15,
1065
        0x02, 0x82, 0x00, 0xa2, 0x22, 0x2a, 0x02, 0x0a,
1066
        0x00, 0x52, 0x0a, 0x15, 0x52, 0x12, 0x15, 0x54,
1067
        0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1068
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1069
 
1070
    // compass south
1071
    unsigned char cd4[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1072
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1073
        0x01, 0x55, 0x54, 0xa8, 0x55, 0x52, 0x02, 0x15,
1074
        0x04, 0x84, 0x40, 0xa1, 0x21, 0x2a, 0x04, 0x48,
1075
        0x40, 0x52, 0x02, 0x15, 0x54, 0xa8, 0x55, 0x55,
1076
        0x01, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1077
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1078
 
1079
    // compass east
1080
    unsigned char cd5[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1081
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54,
1082
        0x00, 0x55, 0x52, 0xaa, 0x15, 0x52, 0x00, 0x55,
1083
        0x02, 0x05, 0x40, 0xa2, 0xa1, 0x2a, 0x02, 0x05,
1084
        0x40, 0x52, 0x00, 0x55, 0x52, 0xaa, 0x15, 0x54,
1085
        0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1086
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1087
 
1088
    // compass west
1089
    unsigned char cd6[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1090
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54,
1091
        0x54, 0x55, 0x52, 0x12, 0x15, 0x52, 0x12, 0x15,
1092
        0x02, 0x02, 0x00, 0xa2, 0x22, 0x2a, 0x02, 0x8a,
1093
        0x00, 0x52, 0x8a, 0x15, 0x52, 0x12, 0x15, 0x54,
1094
        0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1095
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1096
 
1097
    // compass between
1098
    unsigned char cd7[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1099
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1100
        0x55, 0x55, 0x55, 0x45, 0x55, 0x55, 0x21, 0x55,
1101
        0x01, 0x21, 0x00, 0xa8, 0x20, 0xaa, 0x01, 0x21,
1102
        0x00, 0x55, 0x21, 0x55, 0x55, 0x45, 0x55, 0x55,
1103
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1104
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1105
 
326 cascade 1106
    learn_char(208, cd0);
1107
    learn_char(209, cd1);
1108
    learn_char(210, cd2);
1109
    learn_char(211, cd3);
1110
    learn_char(212, cd4);
1111
    learn_char(213, cd5);
1112
    learn_char(214, cd6);
1113
    learn_char(215, cd7);
1114
#endif
1115
#if WRITECHARS == 216
321 cascade 1116
    // compass line
1117
    unsigned char cd8[54] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1118
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1119
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1120
        0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00,
1121
        0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1122
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1123
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1124
 
1125
    // arrow right
1126
    unsigned char cd9[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1127
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1128
        0x55, 0x15, 0x55, 0x54, 0x85, 0x40, 0x00, 0xa1,
1129
        0x2a, 0xaa, 0xa8, 0x2a, 0xaa, 0xa8, 0x40, 0x00,
1130
        0xa1, 0x55, 0x54, 0x85, 0x55, 0x55, 0x15, 0x55,
1131
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1132
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1133
 
1134
    // arrow right-up
1135
    unsigned char cda[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1136
        0x55, 0x55, 0x40, 0x01, 0x55, 0x2a, 0xa8, 0x55,
1137
        0x4a, 0xa8, 0x55, 0x52, 0xa8, 0x55, 0x4a, 0xa8,
1138
        0x55, 0x2a, 0x28, 0x54, 0xa8, 0x48, 0x52, 0xa1,
1139
        0x51, 0x4a, 0x85, 0x55, 0x52, 0x15, 0x55, 0x54,
1140
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1141
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1142
 
1143
    // arrow up
1144
    unsigned char cdb[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1145
        0x55, 0x55, 0x41, 0x55, 0x55, 0x28, 0x55, 0x54,
1146
        0xaa, 0x15, 0x52, 0xaa, 0x85, 0x54, 0x28, 0x15,
1147
        0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28,
1148
        0x55, 0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x55,
1149
        0x28, 0x55, 0x55, 0x41, 0x55, 0x55, 0x55, 0x55,
1150
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1151
 
1152
    // arrow left-up
1153
    unsigned char cdc[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1154
        0x55, 0x40, 0x01, 0x55, 0x2a, 0xa8, 0x55, 0x2a,
1155
        0xa1, 0x55, 0x2a, 0x85, 0x55, 0x2a, 0xa1, 0x55,
1156
        0x28, 0xa8, 0x55, 0x21, 0x2a, 0x15, 0x45, 0x4a,
1157
        0x85, 0x55, 0x52, 0xa1, 0x55, 0x54, 0x85, 0x55,
1158
        0x55, 0x15, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1159
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1160
 
1161
    // arrow left
1162
    unsigned char cdd[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1163
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x54,
1164
        0x55, 0x55, 0x52, 0x15, 0x55, 0x4a, 0x00, 0x01,
1165
        0x2a, 0xaa, 0xa8, 0x2a, 0xaa, 0xa8, 0x4a, 0x00,
1166
        0x01, 0x52, 0x15, 0x55, 0x54, 0x55, 0x55, 0x55,
1167
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1168
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1169
 
1170
    // arrow left-down
1171
    unsigned char cde[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1172
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x55,
1173
        0x54, 0x85, 0x55, 0x52, 0xa1, 0x45, 0x4a, 0x85,
1174
        0x21, 0x2a, 0x15, 0x28, 0xa8, 0x55, 0x2a, 0xa1,
1175
        0x55, 0x2a, 0x85, 0x55, 0x2a, 0xa1, 0x55, 0x2a,
1176
        0xa8, 0x55, 0x40, 0x01, 0x55, 0x55, 0x55, 0x55,
1177
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1178
 
1179
    // arrow down
1180
    unsigned char cdf[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1181
        0x55, 0x55, 0x41, 0x55, 0x55, 0x28, 0x55, 0x55,
1182
        0x28, 0x55, 0x55, 0x28, 0x55, 0x55, 0x28, 0x55,
1183
        0x55, 0x28, 0x55, 0x55, 0x28, 0x55, 0x54, 0x28,
1184
        0x15, 0x52, 0xaa, 0x85, 0x54, 0xaa, 0x15, 0x55,
1185
        0x28, 0x55, 0x55, 0x41, 0x55, 0x55, 0x55, 0x55,
1186
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1187
 
326 cascade 1188
    learn_char(216, cd8);
1189
        learn_char(217, cd9);
1190
    learn_char(218, cda);
1191
    learn_char(219, cdb);
1192
    learn_char(220, cdc);
1193
    learn_char(221, cdd);
1194
    learn_char(222, cde);
1195
    learn_char(223, cdf);
1196
#endif
1197
#if WRITECHARS == 224
1198
     // arrow right-down
321 cascade 1199
    unsigned char ce0[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1200
        0x55, 0x55, 0x55, 0x55, 0x54, 0x55, 0x55, 0x52,
1201
        0x15, 0x55, 0x4a, 0x85, 0x55, 0x52, 0xa1, 0x51,
1202
        0x54, 0xa8, 0x48, 0x55, 0x2a, 0x28, 0x55, 0x4a,
1203
        0xa8, 0x55, 0x52, 0xa8, 0x55, 0x4a, 0xa8, 0x55,
1204
        0x2a, 0xa8, 0x55, 0x40, 0x01, 0x55, 0x55, 0x55,
1205
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1206
 
1207
        // horizon up
1208
    unsigned char ce1[54] ={0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0xaa, 0xaa,
1209
        0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x55,
1210
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1211
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1212
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1213
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1214
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1215
 
1216
        // horizon middle
1217
    unsigned char ce2[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1218
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1219
        0x55, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00,
1220
        0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00,
1221
        0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1222
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1223
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
1224
 
1225
        // horizon down
1226
    unsigned char ce3[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1227
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1228
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1229
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1230
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00,
1231
        0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
1232
        0x00, 0x00, 0x00, 0x55, 0x55, 0x55};
1233
 
1234
        // horizon center
1235
    unsigned char ce4[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1236
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1237
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1238
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1239
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x00,
1240
        0x14, 0x00, 0xaa, 0x14, 0xaa, 0xaa, 0x82, 0xaa,
1241
        0x00, 0xaa, 0x00, 0x54, 0x00, 0x15};
1242
 
1243
        // horizon roll
1244
    unsigned char ce5[54] ={0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1245
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1246
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1247
        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
1248
        0x55, 0x00, 0x55, 0x00, 0x2a, 0x14, 0xa8, 0x4a,
1249
        0x82, 0xa1, 0x52, 0xaa, 0x85, 0x54, 0xaa, 0x15,
1250
        0x55, 0x28, 0x55, 0x55, 0x41, 0x55};
1251
 
1252
        // gps PH
1253
    unsigned char ce6[54] ={0x55, 0x05, 0x11, 0x54, 0xa0, 0x88, 0x54, 0x88,
1254
        0x88, 0x54, 0xa0, 0xa8, 0x54, 0x84, 0x88, 0x44,
1255
        0x84, 0x88, 0x21, 0x15, 0x11, 0xa8, 0x55, 0x55,
1256
        0xa1, 0x55, 0x55, 0x98, 0x15, 0x55, 0x2a, 0x85,
1257
        0x55, 0x4a, 0xa1, 0x55, 0x4a, 0xa8, 0x55, 0x52,
1258
        0xaa, 0x15, 0x54, 0xaa, 0x15, 0x55, 0x28, 0x55,
1259
        0x55, 0x41, 0x55, 0x55, 0x55, 0x55};
1260
 
1261
        // gps CH
1262
    unsigned char ce7[54] ={0x55, 0x55, 0x41, 0x55, 0x55, 0x28, 0x55, 0x54,
1263
        0x81, 0x55, 0x54, 0x85, 0x55, 0x54, 0x81, 0x45,
1264
        0x55, 0x28, 0x21, 0x55, 0x01, 0xa8, 0x54, 0x88,
1265
        0xa1, 0x54, 0x88, 0x98, 0x14, 0xa8, 0x2a, 0x84,
1266
        0x88, 0x4a, 0xa0, 0x88, 0x4a, 0xa8, 0x11, 0x52,
1267
        0xaa, 0x15, 0x54, 0xaa, 0x15, 0x55, 0x28, 0x55,
1268
        0x55, 0x41, 0x55, 0x55, 0x55, 0x55};
1269
 
324 cascade 1270
    learn_char(224, ce0);
321 cascade 1271
        learn_char(225, ce1);
1272
        learn_char(226, ce2);
1273
        learn_char(227, ce3);
1274
        learn_char(228, ce4);
1275
        learn_char(229, ce5);
1276
        learn_char(230, ce6);
324 cascade 1277
        learn_char(231, ce7);
321 cascade 1278
#endif
324 cascade 1279
#endif // write char general
321 cascade 1280
    /* ##########################################################################
1281
     * continue normal main
1282
     * ##########################################################################*/
324 cascade 1283
 
1284
        // Setup Video Mode
1285
        if (COSD_FLAGS & COSD_FLAG_NTSC) {
1286
        // NTSC + enable display immediately (VM0)
1287
        spi_send_byte(0x00, 0b00001000);
1288
        } else {
1289
        // PAL + enable display immediately (VM0)
1290
        spi_send_byte(0x00, 0b01001000);
1291
        }
321 cascade 1292
 
1293
    // clear all display-mem (DMM)
1294
    spi_send_byte(0x04, 0b00000100);
1295
 
1296
    // clearing takes 12uS according to maxim so lets wait longer
1297
    _delay_us(120);
1298
 
1299
    // 8bit mode
1300
    spi_send_byte(0x04, 0b01000000);
1301
 
1302
    // write blank chars to whole screen
1303
    clear();
1304
 
1305
#if !(ALLCHARSDEBUG|WRITECHARS)
1306
    // init usart
1307
    usart1_init();
1308
 
1309
    // set up timer
1310
    TCCR0 |= (1 << CS00) | (1 << CS01); // timer0 prescaler 64
1311
    OCR0 = 6; // preload
1312
    TIMSK |= (1 << TOIE0); // enable overflow timer0
1313
 
326 cascade 1314
    // enable interrupts
321 cascade 1315
    sei();
1316
#endif
1317
 
1318
    //write_ascii_string(2,  7, "         CaScAdE          ");
1319
    //write_ascii_string(2,  8, "is TESTING his open source");
1320
    //write_ascii_string(2,  9, "    EPi OSD Firmware");
1321
 
1322
    // custom char preview
1323
    /*write_char_xy( 2, 7, 200);
1324
    write_char_xy( 3, 7, 201);
1325
    write_char_xy( 4, 7, 202);
1326
    write_char_xy( 5, 7, 203);
1327
    write_char_xy( 6, 7, 204);
1328
    write_char_xy( 7, 7, 205);
1329
    write_char_xy( 8, 7, 206);
1330
    write_char_xy( 9, 7, 207);
1331
    write_char_xy(10, 7, 208);
1332
    write_char_xy(11, 7, 209);
1333
    write_char_xy(12, 7, 210);
1334
    write_char_xy(13, 7, 211);
1335
    write_char_xy(14, 7, 212);
1336
    write_char_xy(15, 7, 213);
1337
    write_char_xy(16, 7, 214);
1338
    write_char_xy(17, 7, 215);*/
1339
 
1340
    // we are ready
1341
    LED3_ON
1342
 
1343
 
1344
 
1345
#if ALLCHARSDEBUG | WRITECHARS
1346
        clear();
1347
    write_all_chars();
1348
#else
1349
    // clear serial screen
1350
    //usart1_puts("\x1B[2J\x1B[H");
1351
    //usart1_puts("hello world!\r\n");
1352
 
1353
 
1354
    // request data ever 100ms from FC
1355
        //unsigned char ms = 10;
1356
        //sendMKData('d', 0, &ms, 1);
1357
 
1358
    // request OSD Data from NC every 100ms
1359
        unsigned char ms = 10;
1360
    sendMKData('o', 1, &ms, 1);
1361
        // and disable debug...
1362
        //ms = 0;
1363
        //sendMKData('d', 0, &ms, 1);
1364
 
1365
        // stats for after flight
1366
        int16_t max_Altimeter = 0;
1367
        uint16_t max_GroundSpeed = 0;
1368
        int16_t max_Distance = 0;
324 cascade 1369
        uint8_t min_UBat = 255;
1370
        uint16_t max_FlyingTime = 0;
321 cascade 1371
 
1372
        // flags from last round to check for changes
1373
        uint8_t old_MKFlags = 0;
1374
 
1375
    char* directions[8] = {"NE", "E ", "SE", "S ", "SW", "W ", "NW", "N "};
1376
        char arrowdir[8] =   { 218,  217,  224,  223,  222,  221,  220, 219};
1377
 
1378
    while (1) {
326 cascade 1379
                // write icons at init or after menu/mode-switch
1380
                if (!(COSD_FLAGS & COSD_ICONS_WRITTEN)) {
1381
                            write_char_xy(5, top_line, 203); // km/h
1382
                            write_char_xy(10, top_line, 202); // RC-transmitter
1383
                            write_char_xy(16, top_line, 208); // degree symbol
1384
                            write_char_xy(27, top_line, 204); // small meters m
1385
                            write_ascii_string(6, bottom_line, "V"); // voltage
1386
                            write_char_xy(14, bottom_line, 209); // on clock
1387
                            write_char_xy(22, bottom_line, 210); // fly clock
1388
                            write_char_xy(26, bottom_line, 200); // sat1
1389
                            write_char_xy(27, bottom_line, 201); // sat2
1390
                                COSD_FLAGS |= COSD_ICONS_WRITTEN;
1391
                }
321 cascade 1392
        if (rxd_buffer_locked) {
1393
            if (rxd_buffer[2] == 'D') { // FC Data
1394
                /*Decode64();
1395
                debugData = *((DebugOut_t*) pRxData);
1396
                write_number_s(12, 2, RxDataLen);
1397
                write_number_s(20, 2, setsReceived++);
1398
                write_number_s(12, 3, debugData.Analog[0]);
1399
                write_number_s(12, 4, debugData.Analog[2]);
1400
                write_number_s(12, 5, debugData.Analog[1]);
1401
                write_number_s(12, 6, debugData.Analog[3]);
1402
                write_number_s(12, 7, debugData.Analog[9]);
1403
                write_number_s(12, 8, debugData.Analog[10]);
1404
                                write_number_s(12, 4, debugData.Analog[12]);
1405
                                write_number_s(12, 5, debugData.Analog[13]);
1406
                                write_number_s(12, 6, debugData.Analog[14]);
1407
                                write_number_s(12, 7, debugData.Analog[15]);*/
1408
            } else if (rxd_buffer[2] == 'O') { // NC OSD Data
1409
                Decode64();
1410
                naviData = *((NaviData_t*) pRxData);
1411
 
1412
                                // first line
1413
                                write_3digit_number_u(2, top_line, (uint16_t)(((uint32_t)naviData.GroundSpeed*36)/1000));
1414
 
1415
                write_3digit_number_u(7, top_line, naviData.RC_Quality);
1416
                if (naviData.RC_Quality <= RCLVL_WRN && last_RC_Quality > RCLVL_WRN) {
1417
                    for (uint8_t x = 0; x < 4; x++)
1418
                        write_char_att_xy(7 + x, top_line, BLINK);
1419
                } else if (naviData.RC_Quality > RCLVL_WRN && last_RC_Quality <= RCLVL_WRN) {
1420
                    for (uint8_t x = 0; x < 4; x++)
1421
                        write_char_att_xy(7 + x, top_line, 0);
1422
                }
1423
                last_RC_Quality = naviData.RC_Quality;
1424
 
1425
                write_3digit_number_u(13, top_line, naviData.CompassHeading);
1426
 
1427
                write_ascii_string(17, top_line, directions[heading_conv(naviData.CompassHeading)]);
1428
 
1429
                if (naviData.Variometer == 0) {
1430
                    write_char_xy(20, top_line, 206); // plain line
1431
                } else if (naviData.Variometer > 0) {
1432
                    write_char_xy(20, top_line, 207); // arrow up
1433
                } else {
1434
                    write_char_xy(20, top_line, 205); // arrow down
1435
                }
1436
 
1437
                                // TODO: is this really dm?
1438
                write_number_s(22, top_line, naviData.Altimeter/10);
1439
 
1440
                                // seccond line
1441
                draw_compass(11, top_line + 1, naviData.CompassHeading);
1442
 
1443
                                // TODO: verify correctness
1444
                                uint16_t heading_home = (naviData.HomePositionDeviation.Bearing + 360 - naviData.CompassHeading) % 360;
1445
                                write_char_xy(27, top_line + 1, arrowdir[heading_conv(heading_home)]);
1446
 
1447
 
1448
                                write_number_s(22, top_line + 1, naviData.HomePositionDeviation.Distance);
1449
 
1450
                                // center
1451
                                if (naviData.MKFlags & FLAG_MOTOR_RUN) { // should be engines running
1452
                                        if (!(old_MKFlags & FLAG_MOTOR_RUN)) { // motors just started, clear middle
1453
                                                for (uint8_t x = 0; x < 30; x++) {
1454
                                                        write_char_xy(x, 5, 0);
1455
                                                        write_char_xy(x, 7, 0);
1456
                                                        write_char_xy(x, 9, 0);
1457
                                                }
1458
                                        }
324 cascade 1459
                                if (COSD_FLAGS & COSD_FLAG_ARTHORIZON) {
1460
                                        draw_artificial_horizon(top_line + 2, bottom_line - 1, naviData.AngleNick, naviData.AngleRoll);
1461
                                }
321 cascade 1462
                                } else {
1463
                                        // stats
1464
                                        write_ascii_string(2, 5, "max Altitude:");
1465
                                        write_number_s(17, 5, max_Altimeter/10);
1466
                                        write_char_xy(22, 5, 204); // small meters m
324 cascade 1467
                                        write_ascii_string(2, 6, "max Speed   :");
1468
                                        write_3digit_number_u(19, 6, (uint16_t)(((uint32_t)max_GroundSpeed*36)/1000));
1469
                                        write_char_xy(22, 6, 203); // km/h
1470
                                        write_ascii_string(2, 7, "max Distance:");
1471
                                        write_number_s(17, 7, max_Distance/100);
1472
                                        write_char_xy(22, 7, 204); // small meters m
1473
                                        write_ascii_string(2, 8, "min voltage :");
1474
                                        //write_number_s(17, 8, min_UBat/10);
1475
                                        write_number_u_10th(16, 8, min_UBat);
1476
                                        write_ascii_string(22, 8, "V"); // voltage
1477
                                        write_ascii_string(2, 9, "max time    :");
1478
                                        write_number_s(17, 9, max_FlyingTime);
1479
                                        write_char_xy(22, 9, 210); // fly clock
321 cascade 1480
                                }
1481
 
1482
                                // bottom line
1483
                write_number_u_10th(0, bottom_line, naviData.UBat);
1484
                if (naviData.UBat <= UBAT_WRN && last_UBat > UBAT_WRN) {
1485
                    for (uint8_t x = 0; x < 7; x++)
1486
                        write_char_att_xy(x, bottom_line, BLINK);
1487
                } else {
1488
                    for (uint8_t x = 0; x < 7; x++)
1489
                        write_char_att_xy(x, bottom_line, 0);
1490
                }
1491
 
1492
                write_time(8, bottom_line, uptime);
1493
                write_time(16, bottom_line, naviData.FlyingTime);
1494
 
1495
                write_3digit_number_u(23, bottom_line, naviData.SatsInUse);
1496
 
1497
                                if (naviData.NCFlags & NC_FLAG_CH) {
1498
                                        write_char_xy(27, bottom_line, 231);    // gps ch
1499
                                } else if (naviData.NCFlags & NC_FLAG_PH) {
1500
                                        write_char_xy(27, bottom_line, 230);    // gps ph
1501
                                } else { // (naviData.NCFlags & NC_FLAG_FREE)
1502
                                        write_char_xy(27, bottom_line, 201);    // sat2 (free)
1503
                                }
1504
 
1505
                //write_number_s(8, 5, RxDataLen);
1506
                //write_number_s(16, 5, setsReceived++);
1507
 
1508
                                // remember statistics
1509
                                if (naviData.Altimeter > max_Altimeter) max_Altimeter = naviData.Altimeter;
1510
                                if (naviData.GroundSpeed > max_GroundSpeed) max_GroundSpeed = naviData.GroundSpeed;
1511
                                if (naviData.HomePositionDeviation.Distance > max_Distance) {
1512
                                        max_Distance = naviData.HomePositionDeviation.Distance;
1513
                                }
324 cascade 1514
                                if (naviData.UBat < min_UBat) min_UBat = naviData.UBat;
1515
                                if (naviData.FlyingTime > max_FlyingTime) max_FlyingTime = naviData.FlyingTime;
1516
 
321 cascade 1517
                                old_MKFlags = naviData.MKFlags;
1518
            }
1519
            rxd_buffer_locked = 0;
1520
        }
1521
        // handle keypress
326 cascade 1522
        if (s1_pressed()) {
321 cascade 1523
                        //sendMKData('d', 1, (unsigned char*) 0, 1);
1524
            // request OSD Data from NC every 100ms
326 cascade 1525
                        /*unsigned char ms = 10;
321 cascade 1526
            sendMKData('o', 1, &ms, 1);
326 cascade 1527
            _delay_ms(500);*/
1528
                        config_menu();
321 cascade 1529
        }
326 cascade 1530
                if (s2_pressed()) {
1531
            uptime = 0;
1532
            _delay_ms(100);
1533
        }
321 cascade 1534
    }
1535
#endif
1536
    return 0;
1537
}