Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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