Subversion Repositories Projects

Rev

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

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