Subversion Repositories Projects

Rev

Rev 724 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
724 woggle 1
/*****************************************************************************
2
 *   Copyright (C) 2009 Peter "woggle" Mack, mac@denich.net                  *
3
 *   - original LCD control by Thomas "thkais" Kaiser                        *
4
 *   - special number formating routines taken from C-OSD                    *
5
 *      from Claas Anders "CaScAdE" Rathje                                   *
6
 *   - some extension, ellipse and circ_line by Peter "woggle" Mack          *
7
 *                                                                           *
8
 *   This program is free software; you can redistribute it and/or modify    *
9
 *   it under the terms of the GNU General Public License as published by    *
10
 *   the Free Software Foundation; either version 2 of the License.          *
11
 *                                                                           *
12
 *   This program is distributed in the hope that it will be useful,         *
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
15
 *   GNU General Public License for more details.                            *
16
 *                                                                           *
17
 *   You should have received a copy of the GNU General Public License       *
18
 *   along with this program; if not, write to the                           *
19
 *   Free Software Foundation, Inc.,                                         *
20
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.               *
21
 *                                                                           *
22
 *****************************************************************************/
23
 
24
#include <avr/io.h>
25
#include <avr/pgmspace.h>
26
#include <util/delay.h>
27
#include <stdlib.h>
28
#include <string.h>
29
#include <math.h>
30
 
31
#include "font8x6.h"
32
#include "font8x8.h"
33
#include "main.h"
34
#include "lcd.h"
35
 
36
 
37
#define DISP_W 128
38
#define DISP_H 64
39
 
40
#define DISP_BUFFER ((DISP_H * DISP_W) / 8)
41
 
42
volatile uint8_t display_buffer[DISP_BUFFER];   // Display-Puffer, weil nicht zurückgelesen werden kann
43
volatile uint16_t display_buffer_pointer;                       // Pointer auf das aktuell übertragene Byte
44
volatile uint8_t display_buffer_counter;                        // Hilfszähler zur Selektierung der Page
45
volatile uint8_t display_page_counter;                          // aktuelle Page-Nummer
46
volatile uint8_t display_mode;                                                          // Modus für State-Machine
47
volatile uint8_t LCD_ORIENTATION;
48
 
49
// DOG: 128 x 64 with 6x8 Font => 21 x 8
50
// MAX7456: 30 x 16
51
 
52
uint8_t lcd_xpos;
53
uint8_t lcd_ypos;
54
 
55
 
56
void send_byte (uint8_t data)
57
{
58
        clr_cs ();
59
        SPDR = data;
60
        while (!(SPSR & (1<<SPIF)));
61
        //SPSR = SPSR;
62
        set_cs ();
63
}
64
 
65
 
66
void lcd_cls (void)
67
{
68
        uint16_t i, j;
69
 
70
//      memset (display_buffer, 0, 1024);
71
        for (i = 0; i < DISP_BUFFER; i++)
72
                display_buffer[i] = 0x00;
73
 
74
        for (i = 0; i < 8; i++)
75
        {
76
                clr_A0 ();
77
                send_byte (0xB0 + i);   //1011xxxx
78
                send_byte (0x10);                       //00010000
79
//              send_byte(0x04);                //00000100 gedreht plus 4 Byte
80
//              send_byte(0x00);                //00000000
81
                send_byte (LCD_ORIENTATION);    //00000000
82
 
83
                set_A0 ();
84
                for (j = 0; j < 128; j++)
85
                        send_byte (0x00);
86
        }
87
 
88
        lcd_xpos = 0;
89
        lcd_ypos = 0;
90
}
91
 
92
void wait_1ms (void)
93
{
94
        _delay_ms (1.0);
95
}
96
 
97
void wait_ms (uint16_t time)
98
{
99
        uint16_t i;
100
 
101
        for (i = 0; i < time; i++)
102
                wait_1ms ();
103
}
104
 
105
void LCD_Init (void)
106
{
107
        lcd_xpos = 0;
108
        lcd_ypos = 0;
109
 
110
        DDRB = 0xFF;
111
 
112
        // SPI max. speed
113
        // the DOGM128 lcd controller can work at 20 MHz
114
        SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPHA) | (1 << CPOL);
115
        SPSR = (1 << SPI2X);
116
 
117
        set_cs ();
118
        clr_reset ();
119
        wait_ms (10);
120
        set_reset ();
121
 
122
        clr_cs ();
123
        clr_A0 ();
124
 
125
        send_byte (0x40);
126
 
127
        if (LCD_ORIENTATION == 0)
128
        {
129
                send_byte (0xA1); // A1 normal A0 reverse(original)
130
                send_byte (0xC0); // C0 normal C8 reverse(original)
131
        }
132
        else
133
        {
134
                send_byte (0xA0); // A1 normal A0 reverse(original)
135
                send_byte (0xC8); // C0 normal C8 reverse(original)
136
        }
137
        send_byte (0xA6);
138
        send_byte (0xA2);
139
        send_byte (0x2F);
140
        send_byte (0xF8);
141
        send_byte (0x00);
142
        send_byte (0x27);
143
        send_byte (0x81);
144
        send_byte (0x16);
145
        send_byte (0xAC);
146
        send_byte (0x00);
147
        send_byte (0xAF);
148
 
149
        lcd_cls ();
150
}
151
 
152
 
153
void set_adress (uint16_t adress, uint8_t data)
154
{
155
        uint8_t page;
156
        uint8_t column;
157
 
158
        page = adress >> 7;
159
 
160
        clr_A0 ();
161
        send_byte (0xB0 + page);
162
 
163
//      column = (adress & 0x7F) + 4; Wenn gedreht
164
//      column = (adress & 0x7F);
165
        column = (adress & 0x7F) + LCD_ORIENTATION;
166
 
167
        send_byte (0x10 + (column >> 4));
168
        send_byte (column & 0x0F);
169
 
170
        set_A0 ();
171
        send_byte (data);
172
}
173
 
174
 
175
void scroll (void)
176
{
177
        uint16_t adress;
178
 
179
        for (adress = 0; adress < 896; adress++)
180
        {
181
                display_buffer[adress] = display_buffer[adress + 128];
182
                set_adress (adress, display_buffer[adress]);
183
        }
184
        for (adress = 896; adress < 1024; adress++)
185
        {
186
                display_buffer[adress] = 0;
187
                set_adress (adress, 0);
188
        }
189
}
190
 
191
 
192
//
193
// x,y = character-Pos. !
194
//
195
// mode: 0=Overwrite, 1 = OR, 2 = XOR, 3 = AND, 4 = Delete
196
void lcd_putc (uint8_t x, uint8_t y, uint8_t c, uint8_t mode)
197
{
198
        uint8_t ch;
199
        uint8_t i;
200
        uint16_t adress;
201
 
202
        switch (c)
203
        {       // ISO 8859-1
204
                case 0xc4:      // Ä
205
                        c = 0x00;
206
                        break;
207
                case 0xe4:      // ä
208
                        c = 0x01;
209
                        break;
210
                case 0xd6:      // Ö
211
                        c = 0x02;
212
                        break;
213
                case 0xf6:      // ö
214
                        c = 0x03;
215
                        break;
216
                case 0xdc:      // Ü
217
                        c = 0x04;
218
                        break;
219
                case 0xfc:      // ü
220
                        c = 0x05;
221
                        break;
222
                case 0xdf:      // ß
223
                        //c = 0x06;
224
                        c = 0x1e; // ° (used by Jeti)
225
                        break;
226
        }
227
 
228
        c &= 0x7f;
229
 
230
        adress = y * 128 + x * 6;
231
        adress &= 0x3FF;
232
 
233
        for (i = 0; i < 6; i++)
234
        {
235
                ch = pgm_read_byte (&font8x6[0][0] + i + c * 6);
236
 
237
                switch (mode)
238
                {
239
                        case 0:
240
                                display_buffer[adress+i] = ch;
241
                                break;
242
                        case 1:
243
                                display_buffer[adress+i] |= ch;
244
                                break;
245
                        case 2:
246
                                display_buffer[adress+i] ^= ch;
247
                                break;
248
                        case 3:
249
                                display_buffer[adress+i] &= ch;
250
                                break;
251
                        case 4:
252
                                display_buffer[adress+i] &= ~ch;
253
                                break;
254
                }
255
 
256
                set_adress (adress + i, display_buffer[adress + i]);
257
        }
258
}
259
 
260
void lcd_putc_jeti (uint8_t x, uint8_t y, uint8_t c, uint8_t mode)
261
{
262
        uint8_t ch;
263
        uint8_t i;
264
        uint16_t adress;
265
 
266
        switch (c)
267
        {
268
                case 0x7e:
269
                        c = 0x1a; // ->
270
                        break;
271
                case 0x7f:
272
                        c = 0x1b; // <-
273
                        break;
274
                case 0xdf:
275
                        c = 0xf8; // °
276
                        break;
277
        }
278
 
279
        adress = y * 128 + x * 8;
280
        adress &= 0x3FF;
281
 
282
        for (i = 0; i < 8; i++)
283
        {
284
                ch = pgm_read_byte (&font8x8[0][0] + i + c * 8);
285
 
286
                switch (mode)
287
                {
288
                        case 0:
289
                                display_buffer[adress+i] = ch;
290
                                break;
291
                        case 1:
292
                                display_buffer[adress+i] |= ch;
293
                                break;
294
                        case 2:
295
                                display_buffer[adress+i] ^= ch;
296
                                break;
297
                        case 3:
298
                                display_buffer[adress+i] &= ch;
299
                                break;
300
                        case 4:
301
                                display_buffer[adress+i] &= ~ch;
302
                                break;
303
                }
304
 
305
                set_adress (adress + i, display_buffer[adress + i]);
306
        }
307
}
308
 
309
 
310
void new_line (void)
311
{
312
        lcd_ypos++;
313
 
314
        if (lcd_ypos > 7)
315
        {
316
                scroll ();
317
                lcd_ypos = 7;
318
        }
319
}
320
 
321
 
322
void lcd_printpj (const char *text, uint8_t mode)
323
{
324
        while (pgm_read_byte(text))
325
        {
326
                switch (pgm_read_byte(text))
327
                {
328
                        case 0x0D:
329
                                lcd_xpos = 0;
330
                                break;
331
                        case 0x0A:
332
                                new_line();
333
                                break;
334
                        default:
335
                                lcd_putc_jeti (lcd_xpos, lcd_ypos, pgm_read_byte(text), mode);
336
 
337
                                lcd_xpos++;
338
                                if (lcd_xpos > 20)
339
                                {
340
                                        lcd_xpos = 0;
341
                                        new_line ();
342
                                }
343
                                break;
344
                }
345
                text++;
346
        }
347
}
348
 
349
 
350
void lcd_printpj_at (uint8_t x, uint8_t y, const char *text, uint8_t mode)
351
{
352
        lcd_xpos = x;
353
        lcd_ypos = y;
354
        lcd_printpj (text, mode);
355
}
356
 
357
 
358
void lcd_printpns (const char *text, uint8_t mode)
359
{
360
        while (pgm_read_byte(text))
361
        {
362
                switch (pgm_read_byte(text))
363
                {
364
                        case 0x0D:
365
                                lcd_xpos = 0;
366
                                break;
367
                        case 0x0A:
368
                                new_line();
369
                                break;
370
                        default:
371
                                lcd_putc (lcd_xpos, lcd_ypos, pgm_read_byte(text), mode);
372
 
373
                                lcd_xpos++;
374
                                if (lcd_xpos > 20)
375
                                {
376
                                        lcd_xpos = 0;
377
//                                      new_line ();
378
                                }
379
                                break;
380
                }
381
                text++;
382
        }
383
}
384
 
385
 
386
void lcd_printpns_at (uint8_t x, uint8_t y, const char *text, uint8_t mode)
387
{
388
        lcd_xpos = x;
389
        lcd_ypos = y;
390
        lcd_printpns (text, mode);
391
}
392
 
393
 
394
void lcd_printp (const char *text, uint8_t mode)
395
{
396
        while (pgm_read_byte(text))
397
        {
398
                switch (pgm_read_byte(text))
399
                {
400
                        case 0x0D:
401
                                lcd_xpos = 0;
402
                                break;
403
                        case 0x0A:
404
                                new_line();
405
                                break;
406
                        default:
407
                                lcd_putc (lcd_xpos, lcd_ypos, pgm_read_byte(text), mode);
408
 
409
                                lcd_xpos++;
410
                                if (lcd_xpos > 20)
411
                                {
412
                                        lcd_xpos = 0;
413
                                        new_line ();
414
                                }
415
                                break;
416
                }
417
                text++;
418
        }
419
}
420
 
421
 
422
void lcd_printp_at (uint8_t x, uint8_t y, const char *text, uint8_t mode)
423
{
424
        lcd_xpos = x;
425
        lcd_ypos = y;
426
        lcd_printp (text, mode);
427
}
428
 
429
 
430
void lcd_print (uint8_t *text, uint8_t mode)
431
{
432
        while (*text)
433
        {
434
                switch (*text)
435
                {
436
                        case 0x0D:
437
                                lcd_xpos = 0;
438
                                break;
439
                        case 0x0A:
440
                                new_line();
441
                                break;
442
                        default:
443
                                lcd_putc (lcd_xpos, lcd_ypos, *text, mode);
444
 
445
                                lcd_xpos++;
446
                                if (lcd_xpos > 20)
447
                                {
448
                                        lcd_xpos = 0;
449
                                        new_line ();
450
                                }
451
                                break;
452
                }
453
                text++;
454
        }
455
}
456
 
457
void lcd_print_at (uint8_t x, uint8_t y, uint8_t *text, uint8_t mode)
458
{
459
        lcd_xpos = x;
460
        lcd_ypos = y;
461
        lcd_print (text, mode);
462
}
463
 
464
 
465
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
466
// + Plot (set one Pixel)
467
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
468
// mode:
469
// 0=Clear, 1=Set, 2=XOR
470
void lcd_plot (uint8_t xpos, uint8_t ypos, uint8_t mode)
471
{
472
        uint16_t adress;
473
        uint8_t mask;
474
 
475
        if ((xpos < DISP_W) && (ypos < DISP_H))
476
        {
477
                adress = (ypos / 8) * DISP_W + xpos;            // adress = 0/8 * 128 + 0   = 0
478
                mask = 1 << (ypos & 0x07);                                      // mask = 1<<0 = 1
479
 
480
                adress &= DISP_BUFFER - 1;
481
 
482
                switch (mode)
483
                {
484
                        case 0:
485
                                display_buffer[adress] &= ~mask;
486
                                break;
487
                        case 1:
488
                                display_buffer[adress] |= mask;
489
                                break;
490
                        case 2:
491
                                display_buffer[adress] ^= mask;
492
                                break;
493
                }
494
 
495
                set_adress (adress, display_buffer[adress]);
496
        }
497
}
498
 
499
 
500
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
501
// + Line (draws a line from x1,y1 to x2,y2
502
// + Based on Bresenham line-Algorithm
503
// + found in the internet, modified by thkais 2007
504
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
505
 
506
void lcd_line (unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, uint8_t mode)
507
{
508
        int x, y, count, xs, ys, xm, ym;
509
 
510
        x = (int) x1;
511
        y = (int) y1;
512
        xs = (int) x2 - (int) x1;
513
        ys = (int) y2 - (int) y1;
514
        if (xs < 0)
515
                xm = -1;
516
        else
517
                if (xs > 0)
518
                        xm = 1;
519
                else
520
                        xm = 0;
521
        if (ys < 0)
522
                ym = -1;
523
        else
524
                if (ys > 0)
525
                        ym = 1;
526
                else
527
                        ym = 0;
528
        if (xs < 0)
529
                xs = -xs;
530
 
531
        if (ys < 0)
532
                ys = -ys;
533
 
534
        lcd_plot ((unsigned char) x, (unsigned char) y, mode);
535
 
536
        if (xs > ys) // Flat Line <45 degrees
537
        {
538
                count = -(xs / 2);
539
                while (x != x2)
540
                {
541
                        count = count + ys;
542
                        x = x + xm;
543
                        if (count > 0)
544
                        {
545
                                y = y + ym;
546
                                count = count - xs;
547
                        }
548
                        lcd_plot ((unsigned char) x, (unsigned char) y, mode);
549
                }
550
        }
551
        else // Line >=45 degrees
552
        {
553
                count =- (ys / 2);
554
                while (y != y2)
555
                {
556
                        count = count + xs;
557
                        y = y + ym;
558
                        if (count > 0)
559
                        {
560
                                x = x + xm;
561
                                count = count - ys;
562
                        }
563
                        lcd_plot ((unsigned char) x, (unsigned char) y, mode);
564
                }
565
        }
566
}
567
 
568
 
569
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
570
// + Filled rectangle
571
// + x1, y1 = upper left corner
572
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
573
 
574
void lcd_frect (uint8_t x1, uint8_t y1, uint8_t widthx, uint8_t widthy, uint8_t mode)
575
{
576
        uint16_t x2, y2;
577
        uint16_t i;
578
 
579
        if (x1 >= DISP_W)
580
                x1 = DISP_W - 1;
581
 
582
        if (y1 >= DISP_H)
583
                y1 = DISP_H - 1;
584
 
585
        x2 = x1 + widthx;
586
        y2 = y1 + widthy;
587
 
588
        if (x2 > DISP_W)
589
                x2 = DISP_W;
590
 
591
        if (y2 > DISP_H)
592
                y2 = DISP_H;
593
 
594
        for (i = y1; i <= y2; i++)
595
        {
596
                lcd_line (x1, i, x2, i, mode);
597
        }
598
}
599
 
600
 
601
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
602
// + outline of rectangle
603
// + x1, y1 = upper left corner
604
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
605
 
606
void lcd_rect (uint8_t x1, uint8_t y1, uint8_t widthx, uint8_t widthy, uint8_t mode)
607
{
608
        uint16_t x2, y2;
609
 
610
        if (x1 >= DISP_W)
611
                x1 = DISP_W - 1;
612
        if (y1 >= DISP_H)
613
                y1 = DISP_H - 1;
614
        x2 = x1 + widthx;
615
        y2 = y1 + widthy;
616
 
617
        if (x2 > DISP_W)
618
                x2 = DISP_W;
619
 
620
        if (y2 > DISP_H)
621
                y2 = DISP_H;
622
 
623
        lcd_line (x1, y1, x2, y1, mode);
624
        lcd_line (x2, y1, x2, y2, mode);
625
        lcd_line (x2, y2, x1, y2, mode);
626
        lcd_line (x1, y2, x1, y1, mode);
627
}
628
 
629
 
630
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
631
// + outline of a circle
632
// + Based on Bresenham-algorithm found in wikipedia
633
// + modified by thkais (2007)
634
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
635
 
636
void lcd_circle (int16_t x0, int16_t y0, int16_t radius, uint8_t mode)
637
{
638
        int16_t f = 1 - radius;
639
        int16_t ddF_x = 0;
640
        int16_t ddF_y = -2 * radius;
641
        int16_t x = 0;
642
        int16_t y = radius;
643
 
644
        lcd_plot (x0, y0 + radius, mode);
645
        lcd_plot (x0, y0 - radius, mode);
646
        lcd_plot (x0 + radius, y0, mode);
647
        lcd_plot (x0 - radius, y0, mode);
648
 
649
        while (x < y)
650
        {
651
                if (f >= 0)
652
                {
653
                        y --;
654
                        ddF_y += 2;
655
                        f += ddF_y;
656
                }
657
                x ++;
658
                ddF_x += 2;
659
                f += ddF_x + 1;
660
 
661
                lcd_plot (x0 + x, y0 + y, mode);
662
                lcd_plot (x0 - x, y0 + y, mode);
663
 
664
                lcd_plot (x0 + x, y0 - y, mode);
665
                lcd_plot (x0 - x, y0 - y, mode);
666
 
667
                lcd_plot (x0 + y, y0 + x, mode);
668
                lcd_plot (x0 - y, y0 + x, mode);
669
 
670
                lcd_plot (x0 + y, y0 - x, mode);
671
                lcd_plot (x0 - y, y0 - x, mode);
672
        }
673
}
674
 
675
 
676
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
677
// + filled Circle
678
// + modified circle-algorithm thkais (2007)
679
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
680
 
681
void lcd_fcircle (int16_t x0, int16_t y0, int16_t radius)
682
{
683
        int16_t f = 1 - radius;
684
        int16_t ddF_x = 0;
685
        int16_t ddF_y = -2 * radius;
686
        int16_t x = 0;
687
        int16_t y = radius;
688
 
689
        lcd_line (x0, y0 + radius, x0, y0 - radius, 1);
690
 
691
        lcd_line (x0 + radius, y0, x0 - radius, y0, 1);
692
 
693
        while (x < y)
694
        {
695
                if (f >= 0)
696
                {
697
                        y--;
698
                        ddF_y += 2;
699
                        f += ddF_y;
700
                }
701
                x++;
702
                ddF_x += 2;
703
                f += ddF_x + 1;
704
 
705
                lcd_line (x0 + x, y0 + y, x0 - x, y0 + y, 1);
706
                lcd_line (x0 + x, y0 - y, x0 - x, y0 - y, 1);
707
                lcd_line (x0 + y, y0 + x, x0 - y, y0 + x, 1);
708
                lcd_line (x0 + y, y0 - x, x0 - y, y0 - x, 1);
709
        }
710
}
711
 
712
//*****************************************************************************
713
// 
714
void lcd_circ_line (uint8_t x, uint8_t y, uint8_t r, uint16_t deg, uint8_t mode)
715
{
716
        uint8_t xc, yc;
717
        double deg_rad;
718
 
719
        deg_rad = (deg * M_PI) / 180.0;
720
 
721
        yc = y - (uint8_t) round (cos (deg_rad) * (double) r);
722
        xc = x + (uint8_t) round (sin (deg_rad) * (double) r);
723
        lcd_line (x, y, xc, yc, mode);
724
}
725
 
726
//*****************************************************************************
727
// 
728
void lcd_ellipse_line (uint8_t x, uint8_t y, uint8_t rx, uint8_t ry, uint16_t deg, uint8_t mode)
729
{
730
        uint8_t xc, yc;
731
        double deg_rad;
732
 
733
        deg_rad = (deg * M_PI) / 180.0;
734
 
735
        yc = y - (uint8_t) round (cos (deg_rad) * (double) ry);
736
        xc = x + (uint8_t) round (sin (deg_rad) * (double) rx);
737
        lcd_line (x, y, xc, yc, mode);
738
}
739
 
740
//*****************************************************************************
741
// 
742
void lcd_ellipse (int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint8_t mode)
743
{
744
        const int16_t rx2 = rx * rx;
745
        const int16_t ry2 = ry * ry;
746
        int16_t F = round (ry2 - rx2 * ry + 0.25 * rx2);
747
        int16_t ddF_x = 0;
748
        int16_t ddF_y = 2 * rx2 * ry;
749
        int16_t x = 0;
750
        int16_t y = ry;
751
 
752
        lcd_plot (x0, y0 + ry, mode);
753
        lcd_plot (x0, y0 - ry, mode);
754
        lcd_plot (x0 + rx, y0, mode);
755
        lcd_plot (x0 - rx, y0, mode);
756
        // while ( 2*ry2*x < 2*rx2*y ) {  we can use ddF_x and ddF_y
757
        while (ddF_x < ddF_y)
758
        {
759
                if(F >= 0)
760
                {
761
                        y     -= 1;        // south
762
                        ddF_y -= 2 * rx2;
763
                        F     -= ddF_y;
764
                }
765
                x     += 1;          // east
766
                ddF_x += 2 * ry2;
767
                F     += ddF_x + ry2;
768
                lcd_plot (x0 + x, y0 + y, mode);
769
                lcd_plot (x0 + x, y0 - y, mode);
770
                lcd_plot (x0 - x, y0 + y, mode);
771
                lcd_plot (x0 - x, y0 - y, mode);
772
        }
773
        F = round (ry2 * (x + 0.5) * (x + 0.5) + rx2 * (y - 1) * (y - 1) - rx2 * ry2);
774
        while(y > 0)
775
        {
776
                if(F <= 0)
777
                {
778
                        x     += 1;        // east
779
                        ddF_x += 2 * ry2;
780
                        F     += ddF_x;
781
                }
782
                y     -=1;           // south
783
                ddF_y -= 2 * rx2;
784
                F     += rx2 - ddF_y;
785
                lcd_plot (x0 + x, y0 + y, mode);
786
                lcd_plot (x0 + x, y0 - y, mode);
787
                lcd_plot (x0 - x, y0 + y, mode);
788
                lcd_plot (x0 - x, y0 - y, mode);
789
        }
790
}
791
 
792
//*****************************************************************************
793
// 
794
void lcd_ecircle (int16_t x0, int16_t y0, int16_t radius, uint8_t mode)
795
{
796
        lcd_ellipse (x0, y0, radius + 3, radius, mode);
797
}
798
 
799
//*****************************************************************************
800
// 
801
void lcd_ecirc_line (uint8_t x, uint8_t y, uint8_t r, uint16_t deg, uint8_t mode)
802
{
803
        lcd_ellipse_line(x, y, r + 3, r, deg, mode);
804
}
805
 
806
//*****************************************************************************
807
// 
808
void lcd_view_font (uint8_t page)
809
{
810
        int x;
811
        int y;
812
 
813
        lcd_cls ();
814
        lcd_printp (PSTR("  0123456789ABCDEF\r\n"), 0);
815
//      lcd_printpns_at (0, 7, PSTR(" \x16    \x17     Exit"), 0);
816
        lcd_printpns_at (0, 7, PSTR(" \x1a    \x1b     Exit"), 0);
817
 
818
        lcd_ypos = 2;
819
        for (y = page * 4 ; y < (page * 4 + 4); y++)
820
        {
821
                if (y < 10)
822
                {
823
                        lcd_putc (0, lcd_ypos, '0' + y, 0);
824
                }
825
                else
826
                {
827
                        lcd_putc (0, lcd_ypos, 'A' + y - 10, 0);
828
                }
829
                lcd_xpos = 2;
830
                for (x = 0; x < 16; x++)
831
                {
832
                        lcd_putc (lcd_xpos, lcd_ypos, y * 16 + x, 0);
833
                        lcd_xpos++;
834
                }
835
                lcd_ypos++;
836
        }
837
}
838
 
839
uint8_t hdigit (uint8_t d)
840
{
841
        if (d < 10)
842
        {
843
                return '0' + d;
844
        }
845
        else
846
        {
847
                return 'A' + d - 10;
848
        }
849
}
850
 
851
void lcd_print_hex_at (uint8_t x, uint8_t y, uint8_t h, uint8_t mode)
852
{
853
        lcd_xpos = x;
854
        lcd_ypos = y;
855
 
856
        lcd_putc (lcd_xpos++, lcd_ypos, hdigit (h >> 4), mode);
857
        lcd_putc (lcd_xpos, lcd_ypos, hdigit (h & 0x0f), mode);
858
}
859
 
860
void lcd_write_number_u (uint8_t number)
861
{
862
        uint8_t num = 100;
863
        uint8_t started = 0;
864
 
865
        while (num > 0)
866
        {
867
                uint8_t b = number / num;
868
                if (b > 0 || started || num == 1)
869
                {
870
                        lcd_putc (lcd_xpos++, lcd_ypos, '0' + b, 0);
871
                        started = 1;
872
                }
873
                number -= b * num;
874
 
875
                num /= 10;
876
        }
877
}
878
 
879
void lcd_write_number_u_at (uint8_t x, uint8_t y, uint8_t number)
880
{
881
        lcd_xpos = x;
882
        lcd_ypos = y;
883
        lcd_write_number_u (number);
884
}
885
 
886
 
887
/**
888
 * Write only some digits of a unsigned <number> at <x>/<y> to MAX7456 display memory
889
 * <num> represents the largest multiple of 10 that will still be displayable as
890
 * the first digit, so num = 10 will be 0-99 and so on
891
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
892
 */
893
void write_ndigit_number_u (uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad)
894
{
895
        char s[7];
896
 
897
        utoa(number, s, 10 );
898
 
899
        uint8_t len = strlen(s);
900
 
901
        if (length < len)
902
        {
903
                for (uint8_t i = 0; i < length; i++)
904
                {
905
                        lcd_putc (x++, y, '*', 0);
906
                }
907
                return;
908
        }
909
 
910
        for (uint8_t i = 0; i < length - len; i++)
911
        {
912
                if (pad)
913
                {
914
                        lcd_putc (x++, y, '0', 0);
915
                }
916
                else
917
                {
918
                        lcd_putc (x++, y, ' ', 0);
919
                }
920
        }
921
        lcd_print_at(x, y, s, 0);
922
}
923
 
924
/**
925
 * Write only some digits of a signed <number> at <x>/<y> to MAX7456 display memory
926
 * <num> represents the largest multiple of 10 that will still be displayable as
927
 * the first digit, so num = 10 will be 0-99 and so on
928
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
929
 */
930
void write_ndigit_number_s (uint8_t x, uint8_t y, int16_t number, int16_t length, uint8_t pad)
931
{
932
        char s[7];
933
 
934
        itoa(number, s, 10 );
935
 
936
        uint8_t len = strlen(s);
937
 
938
        if (length < len)
939
        {
940
                for (uint8_t i = 0; i < length; i++)
941
                {
942
                        lcd_putc (x++, y, '*', 0);
943
                }
944
                return;
945
        }
946
 
947
        for (uint8_t i = 0; i < length - len; i++)
948
        {
949
                if (pad)
950
                {
951
                        lcd_putc (x++, y, '0', 0);
952
                }
953
                else
954
                {
955
                        lcd_putc (x++, y, ' ', 0);
956
                }
957
        }
958
        lcd_print_at(x, y, s, 0);
959
}
960
 
961
/**
962
 * Write only some digits of a unsigned <number> at <x>/<y> to MAX7456 display memory
963
 * as /10th of the value
964
 * <num> represents the largest multiple of 10 that will still be displayable as
965
 * the first digit, so num = 10 will be 0-99 and so on
966
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
967
 */
968
void write_ndigit_number_u_10th (uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad)
969
{
970
        char s[7];
971
 
972
        itoa(number, s, 10 );
973
 
974
        uint8_t len = strlen(s);
975
 
976
        if (length < len)
977
        {
978
                for (uint8_t i = 0; i < length; i++)
979
                {
980
                        lcd_putc (x++, y, '*', 0);
981
                }
982
                return;
983
        }
984
 
985
        for (uint8_t i = 0; i < length - len; i++)
986
        {
987
                if (pad)
988
                {
989
                        lcd_putc (x++, y, '0', 0);
990
                }
991
                else
992
                {
993
                        lcd_putc (x++, y, ' ', 0);
994
                }
995
        }
996
 
997
        char rest = s[len - 1];
998
 
999
        s[len - 1] = 0;
1000
 
1001
        if (len == 1)
1002
        {
1003
                lcd_putc (x-1, y, '0', 0);
1004
        }
1005
        else if (len == 2 && s[0] == '-')
1006
        {
1007
                lcd_putc (x-1, y, '-', 0);
1008
                lcd_putc (x, y, '0', 0);
1009
        }
1010
        else
1011
        {
1012
                lcd_print_at(x, y, s, 0);
1013
        }
1014
        x += len - 1;
1015
        lcd_putc (x++, y, '.', 0);
1016
        lcd_putc (x++, y, rest, 0);
1017
}
1018
 
1019
void write_ndigit_number_u_100th (uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad)
1020
{
1021
        uint8_t num = 100;
1022
 
1023
        while (num > 0)
1024
        {
1025
                uint8_t b = number / num;
1026
 
1027
                if ((num / 10) == 1)
1028
                {
1029
                        lcd_putc (x++, y, '.', 0);
1030
                }
1031
                lcd_putc (x++, y, '0' + b, 0);
1032
                number -= b * num;
1033
 
1034
                num /= 10;
1035
        }
1036
}
1037
 
1038
/**
1039
 * Write only some digits of a signed <number> at <x>/<y> to MAX7456 display memory
1040
 * as /10th of the value
1041
 * <num> represents the largest multiple of 10 that will still be displayable as
1042
 * the first digit, so num = 10 will be 0-99 and so on
1043
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
1044
 */
1045
void write_ndigit_number_s_10th (uint8_t x, uint8_t y, int16_t number, int16_t length, uint8_t pad)
1046
{
1047
        char s[7];
1048
 
1049
        itoa (number, s, 10 );
1050
 
1051
        uint8_t len = strlen(s);
1052
 
1053
        if (length < len)
1054
        {
1055
                for (uint8_t i = 0; i < length; i++)
1056
                {
1057
                        lcd_putc (x++, y, '*', 0);
1058
                }
1059
                return;
1060
        }
1061
 
1062
        for (uint8_t i = 0; i < length - len; i++)
1063
        {
1064
                if (pad)
1065
                {
1066
                        lcd_putc (x++, y, '0', 0);
1067
                }
1068
                else
1069
                {
1070
                        lcd_putc (x++, y, ' ', 0);
1071
                }
1072
        }
1073
 
1074
        char rest = s[len - 1];
1075
 
1076
        s[len - 1] = 0;
1077
 
1078
        if (len == 1)
1079
        {
1080
                lcd_putc (x-1, y, '0', 0);
1081
        }
1082
        else if (len == 2 && s[0] == '-')
1083
        {
1084
                lcd_putc (x-1, y, '-', 0);
1085
                lcd_putc (x, y, '0', 0);
1086
        }
1087
        else
1088
        {
1089
                lcd_print_at(x, y, s, 0);
1090
        }
1091
        x += len - 1;
1092
        lcd_putc (x++, y, '.', 0);
1093
        lcd_putc (x++, y, rest, 0);
1094
}
1095
 
1096
/**
1097
 *  write <seconds> as human readable time at <x>/<y> to MAX7456 display mem
1098
 */
1099
void write_time (uint8_t x, uint8_t y, uint16_t seconds)
1100
{
1101
        uint16_t min = seconds / 60;
1102
        seconds -= min * 60;
1103
        write_ndigit_number_u (x, y, min, 2, 0);
1104
        lcd_putc (x + 2, y, ':', 0);
1105
        write_ndigit_number_u (x + 3, y, seconds, 2, 1);
1106
}
1107
 
1108
/**
1109
 * wirte a <position> at <x>/<y> assuming it is a gps position for long-/latitude
1110
 */
1111
void write_gps_pos (uint8_t x, uint8_t y, int32_t position)
1112
{
1113
        if (position < 0)
1114
        {
1115
                position ^= ~0;
1116
                position++;
1117
                lcd_putc (x++, y, '-', 0);
1118
        }
1119
        else
1120
        {
1121
                lcd_putc (x++, y, ' ', 0);
1122
        }
1123
        write_ndigit_number_u (x, y, (uint16_t) (position / (int32_t) 10000000), 3, 1);
1124
        lcd_putc (x + 3, y, '.', 0);
1125
        position = position - ((position / (int32_t) 10000000) * (int32_t) 10000000);
1126
        write_ndigit_number_u (x + 4, y, (uint16_t) (position / (int32_t) 1000), 4, 1);
1127
        position = position - ((uint16_t) (position / (int32_t) 1000) * (int32_t) 1000);
1128
        write_ndigit_number_u (x + 8, y, (uint16_t) position, 3, 1);
1129
        lcd_putc (x + 11, y, 0x1e, 0);  // degree symbol
1130
}