Subversion Repositories Projects

Rev

Rev 335 | Rev 339 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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