Subversion Repositories Projects

Rev

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