Subversion Repositories Projects

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1053 - 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
#define Jeti 0  // Jeti Routinen
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
 
263
#if Jeti
264
 
265
void lcd_putc_jeti (uint8_t x, uint8_t y, uint8_t c, uint8_t mode)
266
{
267
        uint8_t ch;
268
        uint8_t i;
269
        uint16_t adress;
270
 
271
        switch (c)
272
        {
273
                case 0x7e:
274
                        c = 0x1a; // ->
275
                        break;
276
                case 0x7f:
277
                        c = 0x1b; // <-
278
                        break;
279
                case 0xdf:
280
                        c = 0xf8; // °
281
                        break;
282
        }
283
 
284
        adress = y * 128 + x * 8;
285
        adress &= 0x3FF;
286
 
287
        for (i = 0; i < 8; i++)
288
        {
289
                ch = pgm_read_byte (&font8x8[0][0] + i + c * 8);
290
 
291
                switch (mode)
292
                {
293
                        case 0:
294
                                display_buffer[adress+i] = ch;
295
                                break;
296
                        case 1:
297
                                display_buffer[adress+i] |= ch;
298
                                break;
299
                        case 2:
300
                                display_buffer[adress+i] ^= ch;
301
                                break;
302
                        case 3:
303
                                display_buffer[adress+i] &= ch;
304
                                break;
305
                        case 4:
306
                                display_buffer[adress+i] &= ~ch;
307
                                break;
308
                }
309
 
310
                set_adress (adress + i, display_buffer[adress + i]);
311
        }
312
}
313
 
314
 
315
 
316
 
317
 
318
void lcd_printpj (const char *text, uint8_t mode)
319
{
320
        while (pgm_read_byte(text))
321
        {
322
                switch (pgm_read_byte(text))
323
                {
324
                        case 0x0D:
325
                                lcd_xpos = 0;
326
                                break;
327
                        case 0x0A:
328
                                new_line();
329
                                break;
330
                        default:
331
                                lcd_putc_jeti (lcd_xpos, lcd_ypos, pgm_read_byte(text), mode);
332
 
333
                                lcd_xpos++;
334
                                if (lcd_xpos > 20)
335
                                {
336
                                        lcd_xpos = 0;
337
                                        new_line ();
338
                                }
339
                                break;
340
                }
341
                text++;
342
        }
343
}
344
 
345
 
346
void lcd_printpj_at (uint8_t x, uint8_t y, const char *text, uint8_t mode)
347
{
348
        lcd_xpos = x;
349
        lcd_ypos = y;
350
        lcd_printpj (text, mode);
351
}
352
#endif
353
 
354
void new_line (void)
355
{
356
        lcd_ypos++;
357
 
358
        if (lcd_ypos > 7)
359
        {
360
                scroll ();
361
                lcd_ypos = 7;
362
        }
363
}
364
 
365
 
366
void lcd_printpns (const char *text, uint8_t mode)
367
{
368
        while (pgm_read_byte(text))
369
        {
370
                switch (pgm_read_byte(text))
371
                {
372
                        case 0x0D:
373
                                lcd_xpos = 0;
374
                                break;
375
                        case 0x0A:
376
                                new_line();
377
                                break;
378
                        default:
379
                                lcd_putc (lcd_xpos, lcd_ypos, pgm_read_byte(text), mode);
380
 
381
                                lcd_xpos++;
382
                                if (lcd_xpos > 20)
383
                                {
384
                                        lcd_xpos = 0;
385
//                                      new_line ();
386
                                }
387
                                break;
388
                }
389
                text++;
390
        }
391
}
392
 
393
 
394
void lcd_printpns_at (uint8_t x, uint8_t y, const char *text, uint8_t mode)
395
{
396
        lcd_xpos = x;
397
        lcd_ypos = y;
398
        lcd_printpns (text, mode);
399
}
400
 
401
 
402
void lcd_printp (const char *text, uint8_t mode)
403
{
404
        while (pgm_read_byte(text))
405
        {
406
                switch (pgm_read_byte(text))
407
                {
408
                        case 0x0D:
409
                                lcd_xpos = 0;
410
                                break;
411
                        case 0x0A:
412
                                new_line();
413
                                break;
414
                        default:
415
                                lcd_putc (lcd_xpos, lcd_ypos, pgm_read_byte(text), mode);
416
 
417
                                lcd_xpos++;
418
                                if (lcd_xpos > 20)
419
                                {
420
                                        lcd_xpos = 0;
421
                                        new_line ();
422
                                }
423
                                break;
424
                }
425
                text++;
426
        }
427
}
428
 
429
 
430
void lcd_printp_at (uint8_t x, uint8_t y, const char *text, uint8_t mode)
431
{
432
        lcd_xpos = x;
433
        lcd_ypos = y;
434
        lcd_printp (text, mode);
435
}
436
 
437
 
438
void lcd_print (uint8_t *text, uint8_t mode)
439
{
440
        while (*text)
441
        {
442
                switch (*text)
443
                {
444
                        case 0x0D:
445
                                lcd_xpos = 0;
446
                                break;
447
                        case 0x0A:
448
                                new_line();
449
                                break;
450
                        default:
451
                                lcd_putc (lcd_xpos, lcd_ypos, *text, mode);
452
 
453
                                lcd_xpos++;
454
                                if (lcd_xpos > 20)
455
                                {
456
                                        lcd_xpos = 0;
457
                                        new_line ();
458
                                }
459
                                break;
460
                }
461
                text++;
462
        }
463
}
464
 
465
void lcd_print_at (uint8_t x, uint8_t y, uint8_t *text, uint8_t mode)
466
{
467
        lcd_xpos = x;
468
        lcd_ypos = y;
469
        lcd_print (text, mode);
470
}
471
 
472
 
473
void print_display (uint8_t *text)
474
{
475
        while (*text)
476
        {
477
                lcd_putc (lcd_xpos, lcd_ypos, *text, 0);
478
 
479
                lcd_xpos++;
480
                if (lcd_xpos >= 20)
481
                {
482
                        lcd_xpos = 0;
483
                        new_line ();
484
                }
485
                text++;
486
        }
487
}
488
 
489
void print_display_at (uint8_t x, uint8_t y, uint8_t *text)
490
{
491
        lcd_xpos = x;
492
        lcd_ypos = y;
493
        print_display (text);
494
}
495
 
496
 
497
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
498
// + Plot (set one Pixel)
499
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
500
// mode:
501
// 0=Clear, 1=Set, 2=XOR
502
void lcd_plot (uint8_t xpos, uint8_t ypos, uint8_t mode)
503
{
504
        uint16_t adress;
505
        uint8_t mask;
506
 
507
        if ((xpos < DISP_W) && (ypos < DISP_H))
508
        {
509
                adress = (ypos / 8) * DISP_W + xpos;            // adress = 0/8 * 128 + 0   = 0
510
                mask = 1 << (ypos & 0x07);                                      // mask = 1<<0 = 1
511
 
512
                adress &= DISP_BUFFER - 1;
513
 
514
                switch (mode)
515
                {
516
                        case 0:
517
                                display_buffer[adress] &= ~mask;
518
                                break;
519
                        case 1:
520
                                display_buffer[adress] |= mask;
521
                                break;
522
                        case 2:
523
                                display_buffer[adress] ^= mask;
524
                                break;
525
                }
526
 
527
                set_adress (adress, display_buffer[adress]);
528
        }
529
}
530
 
531
 
532
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
533
// + Line (draws a line from x1,y1 to x2,y2
534
// + Based on Bresenham line-Algorithm
535
// + found in the internet, modified by thkais 2007
536
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
537
 
538
void lcd_line (unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, uint8_t mode)
539
{
540
        int x, y, count, xs, ys, xm, ym;
541
 
542
        x = (int) x1;
543
        y = (int) y1;
544
        xs = (int) x2 - (int) x1;
545
        ys = (int) y2 - (int) y1;
546
        if (xs < 0)
547
                xm = -1;
548
        else
549
                if (xs > 0)
550
                        xm = 1;
551
                else
552
                        xm = 0;
553
        if (ys < 0)
554
                ym = -1;
555
        else
556
                if (ys > 0)
557
                        ym = 1;
558
                else
559
                        ym = 0;
560
        if (xs < 0)
561
                xs = -xs;
562
 
563
        if (ys < 0)
564
                ys = -ys;
565
 
566
        lcd_plot ((unsigned char) x, (unsigned char) y, mode);
567
 
568
        if (xs > ys) // Flat Line <45 degrees
569
        {
570
                count = -(xs / 2);
571
                while (x != x2)
572
                {
573
                        count = count + ys;
574
                        x = x + xm;
575
                        if (count > 0)
576
                        {
577
                                y = y + ym;
578
                                count = count - xs;
579
                        }
580
                        lcd_plot ((unsigned char) x, (unsigned char) y, mode);
581
                }
582
        }
583
        else // Line >=45 degrees
584
        {
585
                count =- (ys / 2);
586
                while (y != y2)
587
                {
588
                        count = count + xs;
589
                        y = y + ym;
590
                        if (count > 0)
591
                        {
592
                                x = x + xm;
593
                                count = count - ys;
594
                        }
595
                        lcd_plot ((unsigned char) x, (unsigned char) y, mode);
596
                }
597
        }
598
}
599
 
600
 
601
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
602
// + Filled rectangle
603
// + x1, y1 = upper left corner
604
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
605
 
606
void lcd_frect (uint8_t x1, uint8_t y1, uint8_t widthx, uint8_t widthy, uint8_t mode)
607
{
608
        uint16_t x2, y2;
609
        uint16_t i;
610
 
611
        if (x1 >= DISP_W)
612
                x1 = DISP_W - 1;
613
 
614
        if (y1 >= DISP_H)
615
                y1 = DISP_H - 1;
616
 
617
        x2 = x1 + widthx;
618
        y2 = y1 + widthy;
619
 
620
        if (x2 > DISP_W)
621
                x2 = DISP_W;
622
 
623
        if (y2 > DISP_H)
624
                y2 = DISP_H;
625
 
626
        for (i = y1; i <= y2; i++)
627
        {
628
                lcd_line (x1, i, x2, i, mode);
629
        }
630
}
631
 
632
 
633
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
634
// + outline of rectangle
635
// + x1, y1 = upper left corner
636
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
637
 
638
void lcd_rect (uint8_t x1, uint8_t y1, uint8_t widthx, uint8_t widthy, uint8_t mode)
639
{
640
        uint16_t x2, y2;
641
 
642
        if (x1 >= DISP_W)
643
                x1 = DISP_W - 1;
644
        if (y1 >= DISP_H)
645
                y1 = DISP_H - 1;
646
        x2 = x1 + widthx;
647
        y2 = y1 + widthy;
648
 
649
        if (x2 > DISP_W)
650
                x2 = DISP_W;
651
 
652
        if (y2 > DISP_H)
653
                y2 = DISP_H;
654
 
655
        lcd_line (x1, y1, x2, y1, mode);
656
        lcd_line (x2, y1, x2, y2, mode);
657
        lcd_line (x2, y2, x1, y2, mode);
658
        lcd_line (x1, y2, x1, y1, mode);
659
}
660
 
661
 
662
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
663
// + outline of a circle
664
// + Based on Bresenham-algorithm found in wikipedia
665
// + modified by thkais (2007)
666
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
667
 
668
void lcd_circle (int16_t x0, int16_t y0, int16_t radius, uint8_t mode)
669
{
670
        int16_t f = 1 - radius;
671
        int16_t ddF_x = 0;
672
        int16_t ddF_y = -2 * radius;
673
        int16_t x = 0;
674
        int16_t y = radius;
675
 
676
        lcd_plot (x0, y0 + radius, mode);
677
        lcd_plot (x0, y0 - radius, mode);
678
        lcd_plot (x0 + radius, y0, mode);
679
        lcd_plot (x0 - radius, y0, mode);
680
 
681
        while (x < y)
682
        {
683
                if (f >= 0)
684
                {
685
                        y --;
686
                        ddF_y += 2;
687
                        f += ddF_y;
688
                }
689
                x ++;
690
                ddF_x += 2;
691
                f += ddF_x + 1;
692
 
693
                lcd_plot (x0 + x, y0 + y, mode);
694
                lcd_plot (x0 - x, y0 + y, mode);
695
 
696
                lcd_plot (x0 + x, y0 - y, mode);
697
                lcd_plot (x0 - x, y0 - y, mode);
698
 
699
                lcd_plot (x0 + y, y0 + x, mode);
700
                lcd_plot (x0 - y, y0 + x, mode);
701
 
702
                lcd_plot (x0 + y, y0 - x, mode);
703
                lcd_plot (x0 - y, y0 - x, mode);
704
        }
705
}
706
 
707
 
708
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
709
// + filled Circle
710
// + modified circle-algorithm thkais (2007)
711
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
712
 
713
void lcd_fcircle (int16_t x0, int16_t y0, int16_t radius)
714
{
715
        int16_t f = 1 - radius;
716
        int16_t ddF_x = 0;
717
        int16_t ddF_y = -2 * radius;
718
        int16_t x = 0;
719
        int16_t y = radius;
720
 
721
        lcd_line (x0, y0 + radius, x0, y0 - radius, 1);
722
 
723
        lcd_line (x0 + radius, y0, x0 - radius, y0, 1);
724
 
725
        while (x < y)
726
        {
727
                if (f >= 0)
728
                {
729
                        y--;
730
                        ddF_y += 2;
731
                        f += ddF_y;
732
                }
733
                x++;
734
                ddF_x += 2;
735
                f += ddF_x + 1;
736
 
737
                lcd_line (x0 + x, y0 + y, x0 - x, y0 + y, 1);
738
                lcd_line (x0 + x, y0 - y, x0 - x, y0 - y, 1);
739
                lcd_line (x0 + y, y0 + x, x0 - y, y0 + x, 1);
740
                lcd_line (x0 + y, y0 - x, x0 - y, y0 - x, 1);
741
        }
742
}
743
 
744
//*****************************************************************************
745
// 
746
void lcd_circ_line (uint8_t x, uint8_t y, uint8_t r, uint16_t deg, uint8_t mode)
747
{
748
        uint8_t xc, yc;
749
        double deg_rad;
750
 
751
        deg_rad = (deg * M_PI) / 180.0;
752
 
753
        yc = y - (uint8_t) round (cos (deg_rad) * (double) r);
754
        xc = x + (uint8_t) round (sin (deg_rad) * (double) r);
755
        lcd_line (x, y, xc, yc, mode);
756
}
757
 
758
//*****************************************************************************
759
// 
760
void lcd_ellipse_line (uint8_t x, uint8_t y, uint8_t rx, uint8_t ry, uint16_t deg, uint8_t mode)
761
{
762
        uint8_t xc, yc;
763
        double deg_rad;
764
 
765
        deg_rad = (deg * M_PI) / 180.0;
766
 
767
        yc = y - (uint8_t) round (cos (deg_rad) * (double) ry);
768
        xc = x + (uint8_t) round (sin (deg_rad) * (double) rx);
769
        lcd_line (x, y, xc, yc, mode);
770
}
771
 
772
//*****************************************************************************
773
// 
774
void lcd_ellipse (int16_t x0, int16_t y0, int16_t rx, int16_t ry, uint8_t mode)
775
{
776
        const int16_t rx2 = rx * rx;
777
        const int16_t ry2 = ry * ry;
778
        int16_t F = round (ry2 - rx2 * ry + 0.25 * rx2);
779
        int16_t ddF_x = 0;
780
        int16_t ddF_y = 2 * rx2 * ry;
781
        int16_t x = 0;
782
        int16_t y = ry;
783
 
784
        lcd_plot (x0, y0 + ry, mode);
785
        lcd_plot (x0, y0 - ry, mode);
786
        lcd_plot (x0 + rx, y0, mode);
787
        lcd_plot (x0 - rx, y0, mode);
788
        // while ( 2*ry2*x < 2*rx2*y ) {  we can use ddF_x and ddF_y
789
        while (ddF_x < ddF_y)
790
        {
791
                if(F >= 0)
792
                {
793
                        y     -= 1;        // south
794
                        ddF_y -= 2 * rx2;
795
                        F     -= ddF_y;
796
                }
797
                x     += 1;          // east
798
                ddF_x += 2 * ry2;
799
                F     += ddF_x + ry2;
800
                lcd_plot (x0 + x, y0 + y, mode);
801
                lcd_plot (x0 + x, y0 - y, mode);
802
                lcd_plot (x0 - x, y0 + y, mode);
803
                lcd_plot (x0 - x, y0 - y, mode);
804
        }
805
        F = round (ry2 * (x + 0.5) * (x + 0.5) + rx2 * (y - 1) * (y - 1) - rx2 * ry2);
806
        while(y > 0)
807
        {
808
                if(F <= 0)
809
                {
810
                        x     += 1;        // east
811
                        ddF_x += 2 * ry2;
812
                        F     += ddF_x;
813
                }
814
                y     -=1;           // south
815
                ddF_y -= 2 * rx2;
816
                F     += rx2 - ddF_y;
817
                lcd_plot (x0 + x, y0 + y, mode);
818
                lcd_plot (x0 + x, y0 - y, mode);
819
                lcd_plot (x0 - x, y0 + y, mode);
820
                lcd_plot (x0 - x, y0 - y, mode);
821
        }
822
}
823
 
824
//*****************************************************************************
825
// 
826
void lcd_ecircle (int16_t x0, int16_t y0, int16_t radius, uint8_t mode)
827
{
828
        lcd_ellipse (x0, y0, radius + 3, radius, mode);
829
}
830
 
831
//*****************************************************************************
832
// 
833
void lcd_ecirc_line (uint8_t x, uint8_t y, uint8_t r, uint16_t deg, uint8_t mode)
834
{
835
        lcd_ellipse_line(x, y, r + 3, r, deg, mode);
836
}
837
 
838
//*****************************************************************************
839
// 
840
void lcd_view_font (uint8_t page)
841
{
842
        int x;
843
        int y;
844
 
845
        lcd_cls ();
846
        lcd_printp (PSTR("  0123456789ABCDEF\r\n"), 0);
847
//      lcd_printpns_at (0, 7, PSTR(" \x16    \x17     Exit"), 0);
848
        lcd_printpns_at (0, 7, PSTR(" \x1a    \x1b     Exit"), 0);
849
 
850
        lcd_ypos = 2;
851
        for (y = page * 4 ; y < (page * 4 + 4); y++)
852
        {
853
                if (y < 10)
854
                {
855
                        lcd_putc (0, lcd_ypos, '0' + y, 0);
856
                }
857
                else
858
                {
859
                        lcd_putc (0, lcd_ypos, 'A' + y - 10, 0);
860
                }
861
                lcd_xpos = 2;
862
                for (x = 0; x < 16; x++)
863
                {
864
                        lcd_putc (lcd_xpos, lcd_ypos, y * 16 + x, 0);
865
                        lcd_xpos++;
866
                }
867
                lcd_ypos++;
868
        }
869
}
870
 
871
uint8_t hdigit (uint8_t d)
872
{
873
        if (d < 10)
874
        {
875
                return '0' + d;
876
        }
877
        else
878
        {
879
                return 'A' + d - 10;
880
        }
881
}
882
 
883
void lcd_print_hex_at (uint8_t x, uint8_t y, uint8_t h, uint8_t mode)
884
{
885
        lcd_xpos = x;
886
        lcd_ypos = y;
887
 
888
        lcd_putc (lcd_xpos++, lcd_ypos, hdigit (h >> 4), mode);
889
        lcd_putc (lcd_xpos, lcd_ypos, hdigit (h & 0x0f), mode);
890
}
891
 
892
void lcd_print_hex (uint8_t h, uint8_t mode)
893
{
894
//      lcd_xpos = x;
895
//      lcd_ypos = y;
896
 
897
        lcd_putc (lcd_xpos++, lcd_ypos, hdigit (h >> 4), mode);
898
        lcd_putc (lcd_xpos++, lcd_ypos, hdigit (h & 0x0f), mode);
899
        lcd_putc (lcd_xpos++, lcd_ypos, ' ', mode);
900
}
901
void lcd_write_number_u (uint8_t number)
902
{
903
        uint8_t num = 100;
904
        uint8_t started = 0;
905
 
906
        while (num > 0)
907
        {
908
                uint8_t b = number / num;
909
                if (b > 0 || started || num == 1)
910
                {
911
                        lcd_putc (lcd_xpos++, lcd_ypos, '0' + b, 0);
912
                        started = 1;
913
                }
914
                number -= b * num;
915
 
916
                num /= 10;
917
        }
918
}
919
 
920
void lcd_write_number_u_at (uint8_t x, uint8_t y, uint8_t number)
921
{
922
        lcd_xpos = x;
923
        lcd_ypos = y;
924
        lcd_write_number_u (number);
925
}
926
 
927
 
928
/**
929
 * Write only some digits of a unsigned <number> at <x>/<y> to MAX7456 display memory
930
 * <num> represents the largest multiple of 10 that will still be displayable as
931
 * the first digit, so num = 10 will be 0-99 and so on
932
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
933
 */
934
void write_ndigit_number_u (uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad)
935
{
936
        char s[7];
937
 
938
        utoa(number, s, 10 );
939
 
940
        uint8_t len = strlen(s);
941
 
942
        if (length < len)
943
        {
944
                for (uint8_t i = 0; i < length; i++)
945
                {
946
                        lcd_putc (x++, y, '*', 0);
947
                }
948
                return;
949
        }
950
 
951
        for (uint8_t i = 0; i < length - len; i++)
952
        {
953
                if (pad)
954
                {
955
                        lcd_putc (x++, y, '0', 0);
956
                }
957
                else
958
                {
959
                        lcd_putc (x++, y, ' ', 0);
960
                }
961
        }
962
        lcd_print_at(x, y, (uint8_t*)s, 0);
963
}
964
 
965
/**
966
 * Write only some digits of a signed <number> at <x>/<y> to MAX7456 display memory
967
 * <num> represents the largest multiple of 10 that will still be displayable as
968
 * the first digit, so num = 10 will be 0-99 and so on
969
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
970
 */
971
void write_ndigit_number_s (uint8_t x, uint8_t y, int16_t number, int16_t length, uint8_t pad)
972
{
973
        char s[7];
974
 
975
        itoa(number, s, 10 );
976
 
977
        uint8_t len = strlen(s);
978
 
979
        if (length < len)
980
        {
981
                for (uint8_t i = 0; i < length; i++)
982
                {
983
                        lcd_putc (x++, y, '*', 0);
984
                }
985
                return;
986
        }
987
 
988
        for (uint8_t i = 0; i < length - len; i++)
989
        {
990
                if (pad)
991
                {
992
                        lcd_putc (x++, y, '0', 0);
993
                }
994
                else
995
                {
996
                        lcd_putc (x++, y, ' ', 0);
997
                }
998
        }
999
        lcd_print_at(x, y, (uint8_t*)s, 0);
1000
}
1001
 
1002
/**
1003
 * Write only some digits of a unsigned <number> at <x>/<y> to MAX7456 display memory
1004
 * as /10th of the value
1005
 * <num> represents the largest multiple of 10 that will still be displayable as
1006
 * the first digit, so num = 10 will be 0-99 and so on
1007
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
1008
 */
1009
void write_ndigit_number_u_10th (uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad)
1010
{
1011
        char s[7];
1012
 
1013
        itoa(number, s, 10 );
1014
 
1015
        uint8_t len = strlen(s);
1016
 
1017
        if (length < len)
1018
        {
1019
                for (uint8_t i = 0; i < length; i++)
1020
                {
1021
                        lcd_putc (x++, y, '*', 0);
1022
                }
1023
                return;
1024
        }
1025
 
1026
        for (uint8_t i = 0; i < length - len; i++)
1027
        {
1028
                if (pad)
1029
                {
1030
                        lcd_putc (x++, y, '0', 0);
1031
                }
1032
                else
1033
                {
1034
                        lcd_putc (x++, y, ' ', 0);
1035
                }
1036
        }
1037
 
1038
        char rest = s[len - 1];
1039
 
1040
        s[len - 1] = 0;
1041
 
1042
        if (len == 1)
1043
        {
1044
                lcd_putc (x-1, y, '0', 0);
1045
        }
1046
        else if (len == 2 && s[0] == '-')
1047
        {
1048
                lcd_putc (x-1, y, '-', 0);
1049
                lcd_putc (x, y, '0', 0);
1050
        }
1051
        else
1052
        {
1053
                lcd_print_at(x, y, (uint8_t*)s, 0);
1054
        }
1055
        x += len - 1;
1056
        lcd_putc (x++, y, '.', 0);
1057
        lcd_putc (x++, y, rest, 0);
1058
}
1059
 
1060
void write_ndigit_number_u_100th (uint8_t x, uint8_t y, uint16_t number, int16_t length, uint8_t pad)
1061
{
1062
        uint8_t num = 100;
1063
 
1064
        while (num > 0)
1065
        {
1066
                uint8_t b = number / num;
1067
 
1068
                if ((num / 10) == 1)
1069
                {
1070
                        lcd_putc (x++, y, '.', 0);
1071
                }
1072
                lcd_putc (x++, y, '0' + b, 0);
1073
                number -= b * num;
1074
 
1075
                num /= 10;
1076
        }
1077
}
1078
 
1079
/**
1080
 * Write only some digits of a signed <number> at <x>/<y> to MAX7456 display memory
1081
 * as /10th of the value
1082
 * <num> represents the largest multiple of 10 that will still be displayable as
1083
 * the first digit, so num = 10 will be 0-99 and so on
1084
 * <pad> = 1 will cause blank spaced to be filled up with zeros e.g. 007 instead of   7
1085
 */
1086
void write_ndigit_number_s_10th (uint8_t x, uint8_t y, int16_t number, int16_t length, uint8_t pad)
1087
{
1088
        char s[7];
1089
 
1090
        itoa (number, s, 10 );
1091
 
1092
        uint8_t len = strlen(s);
1093
 
1094
        if (length < len)
1095
        {
1096
                for (uint8_t i = 0; i < length; i++)
1097
                {
1098
                        lcd_putc (x++, y, '*', 0);
1099
                }
1100
                return;
1101
        }
1102
 
1103
        for (uint8_t i = 0; i < length - len; i++)
1104
        {
1105
                if (pad)
1106
                {
1107
                        lcd_putc (x++, y, '0', 0);
1108
                }
1109
                else
1110
                {
1111
                        lcd_putc (x++, y, ' ', 0);
1112
                }
1113
        }
1114
 
1115
        char rest = s[len - 1];
1116
 
1117
        s[len - 1] = 0;
1118
 
1119
        if (len == 1)
1120
        {
1121
                lcd_putc (x-1, y, '0', 0);
1122
        }
1123
        else if (len == 2 && s[0] == '-')
1124
        {
1125
                lcd_putc (x-1, y, '-', 0);
1126
                lcd_putc (x, y, '0', 0);
1127
        }
1128
        else
1129
        {
1130
                lcd_print_at(x, y, (uint8_t*)s, 0);
1131
        }
1132
        x += len - 1;
1133
        lcd_putc (x++, y, '.', 0);
1134
        lcd_putc (x++, y, rest, 0);
1135
}
1136
 
1137
/**
1138
 *  write <seconds> as human readable time at <x>/<y> to MAX7456 display mem
1139
 */
1140
void write_time (uint8_t x, uint8_t y, uint16_t seconds)
1141
{
1142
        uint16_t min = seconds / 60;
1143
        seconds -= min * 60;
1144
        write_ndigit_number_u (x, y, min, 2, 0);
1145
        lcd_putc (x + 2, y, ':', 0);
1146
        write_ndigit_number_u (x + 3, y, seconds, 2, 1);
1147
}
1148
 
1149
/**
1150
 * wirte a <position> at <x>/<y> assuming it is a gps position for long-/latitude
1151
 */
1152
void write_gps_pos (uint8_t x, uint8_t y, int32_t position)
1153
{
1154
        if (position < 0)
1155
        {
1156
                position ^= ~0;
1157
                position++;
1158
                lcd_putc (x++, y, '-', 0);
1159
        }
1160
        else
1161
        {
1162
                lcd_putc (x++, y, ' ', 0);
1163
        }
1164
        write_ndigit_number_u (x, y, (uint16_t) (position / (int32_t) 10000000), 3, 1);
1165
        lcd_putc (x + 3, y, '.', 0);
1166
        position = position - ((position / (int32_t) 10000000) * (int32_t) 10000000);
1167
        write_ndigit_number_u (x + 4, y, (uint16_t) (position / (int32_t) 1000), 4, 1);
1168
        position = position - ((uint16_t) (position / (int32_t) 1000) * (int32_t) 1000);
1169
        write_ndigit_number_u (x + 8, y, (uint16_t) position, 3, 1);
1170
        lcd_putc (x + 11, y, 0x1e, 0);  // degree symbol
1171
}