Subversion Repositories Projects

Rev

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