mirror of
https://github.com/travisgoodspeed/goodwatch
synced 2024-11-21 23:58:31 +00:00
300 lines
6.6 KiB
C
300 lines
6.6 KiB
C
/*! \file lcdtext.c
|
|
\brief LCD font and text drawing functions.
|
|
*/
|
|
#include "lcd.h"
|
|
#include "lcdtext.h"
|
|
#include "optim.h"
|
|
|
|
/* Digits look like this, and we index them with 0 being the
|
|
leftmost.
|
|
|
|
AAAAA
|
|
F B
|
|
F B
|
|
F B
|
|
GGGGG
|
|
E C
|
|
E C
|
|
E C
|
|
DDDDD dp
|
|
|
|
*/
|
|
|
|
|
|
//! This maps the segments of each digit.
|
|
const int lcdmap[10][8]={
|
|
// A, B, C, D, E, F, G, dp digit
|
|
{0x0b04, 0x0b40, 0x0b20, 0x0b01, 0x0a10, 0x0a20, 0x0b02, 0x0b10}, //0
|
|
{0x0940, 0x0a04, 0x0a02, 0x0910, 0x0901, 0x0902, 0x0920, 0x0a01}, //1
|
|
{0x0804, 0x0840, 0x0820, 0x0801, 0x0710, 0x0720, 0x0802, 0x0810}, //2
|
|
{0x0640, 0x0704, 0x0702, 0x0610, 0x0601, 0x0602, 0x0620, 0x0701}, //3
|
|
{0x0504, 0x0540, 0x0520, 0x0501, 0x0410, 0x0420, 0x0502, 0x0510}, //4
|
|
{0x0c02, 0x0404, 0x0402, 0x0310, 0x0302, 0x0304, 0x0340, 0x0401}, //5
|
|
{0x0204, 0x0220, 0x0210, 0x0201, 0x0110, 0x0120, 0x0202, 0x0301}, //6
|
|
{0x0040, 0x0104, 0x0102, 0x0010, 0x0001, 0x0002, 0x0020, 0x0101}, //7
|
|
};
|
|
|
|
//These are the fragments of the day of the week: 0x0904, 0x0a40, 0x0c01
|
|
//0x0c10 is beyond the screen.
|
|
|
|
//! Bit flags for each of the eight segments.
|
|
enum lcdmappos {A=1, B=2, C=4, D=8, E=0x10, F=0x20, G=0x40, DP=0x80};
|
|
|
|
|
|
//! Font for numbers.
|
|
const int numfont[]={
|
|
A|B|C|D|E|F, //0
|
|
B|C, //1
|
|
A|B|G|E|D, //2
|
|
A|B|G|C|D, //3
|
|
F|G|B|C, //4
|
|
A|F|G|C|D, //5
|
|
A|F|G|E|C|D, //6
|
|
A|B|C, //7
|
|
A|B|C|D|E|F|G, //8
|
|
A|B|G|F|C|D, //9
|
|
A|F|B|G|E|C, //A
|
|
F|E|G|C|D, //B
|
|
A|F|E|D, //C
|
|
E|G|C|D|B, //D
|
|
A|F|E|G|D, //E
|
|
A|G|F|E //F
|
|
};
|
|
//! Font for letters.
|
|
const int letterfont[]={
|
|
/* This font begins at 0x41 hex in the ASCII table, rendering
|
|
letters as best they can be on the 7-segment display.
|
|
*/
|
|
A|F|B|G|E|C, //A
|
|
F|E|G|C|D, //B
|
|
A|F|E|D, //C
|
|
E|G|C|D|B, //D
|
|
A|F|E|G|D, //E
|
|
A|G|F|E, //F
|
|
A|F|G|E|C|D, //G
|
|
F|G|E|C, //h
|
|
F|E, //I, distinguished from a 1 by being on the left side.
|
|
E|B|C|D, //J
|
|
F|E|B|C|G|DP, //K, distinguished from an X by the DP.
|
|
F|E|D, //L
|
|
A|E|C, //M (Less nerdy than mu, but more readable.)
|
|
E|G|C, //n
|
|
A|B|C|D|E|F, //O
|
|
F|A|B|G|E, //P
|
|
F|A|B|C|D|E|DP,//Q
|
|
E|G, //R
|
|
A|F|G|C|D, //S (Looks like a 5.)
|
|
F|E|G|D, //T
|
|
E|D|C, //U (Like a lowercase V)
|
|
F|E|D|C|B, //V (Like U. Blame Rome.)
|
|
F|B|D, //W (Inverted M)
|
|
F|G|E|B|C, //X
|
|
F|G|B|C|D, //Y
|
|
A|B|G|E|D //Z
|
|
};
|
|
|
|
//! Sets a pixel.
|
|
#define DRAWPOINT(todraw) lcdm[todraw>>8]|=todraw&0xFF
|
|
//! Clears a pixel.
|
|
#define CLEARPOINT(todraw) lcdm[todraw>>8]&=~(todraw&0xFF)
|
|
|
|
|
|
//! Draws one LCD digit.
|
|
void lcd_digit(int pos, int digit){
|
|
int segments=numfont[digit];
|
|
int bit;
|
|
for(bit=0;bit<8;bit++){
|
|
if(segments&(1<<bit))
|
|
DRAWPOINT(lcdmap[pos][bit]);
|
|
else
|
|
CLEARPOINT(lcdmap[pos][bit]);
|
|
}
|
|
}
|
|
|
|
//! Draws one LCD character
|
|
void lcd_char(int pos, char c){
|
|
int segments;//=numfont[digit];
|
|
int bit;
|
|
|
|
//Numbers handled by another function until we unify the font.
|
|
if(c>='0' && c<='9'){
|
|
lcd_digit(pos, c&0x0F);
|
|
return;
|
|
}else if(c==' '){
|
|
lcd_cleardigit(pos);
|
|
return;
|
|
}else if(c=='-'){
|
|
lcd_cleardigit(pos);
|
|
DRAWPOINT(lcdmap[pos][6]); //Set the G segment.
|
|
return;
|
|
}else if(c=='.'){
|
|
lcd_cleardigit(pos);
|
|
setperiod(pos,1);
|
|
return;
|
|
}
|
|
|
|
c&=~0x20;
|
|
segments=letterfont[c-'A'];
|
|
|
|
for(bit=0;bit<8;bit++){
|
|
if(segments&(1<<bit))
|
|
DRAWPOINT(lcdmap[pos][bit]);
|
|
else
|
|
CLEARPOINT(lcdmap[pos][bit]);
|
|
}
|
|
}
|
|
|
|
//! Clears one LCD digit.
|
|
void lcd_cleardigit(int pos){
|
|
int bit;
|
|
for(bit=0;bit<8;bit++)
|
|
CLEARPOINT(lcdmap[pos][bit]);
|
|
|
|
}
|
|
|
|
//! Draws a string to the LCD.
|
|
void lcd_string(const char *str){
|
|
int i=7;//LCD position.
|
|
while(i>=0 && *str){
|
|
lcd_char(i--, *str++);
|
|
}
|
|
}
|
|
|
|
//! Draws a decimal number on the screen.
|
|
void lcd_unumber(long num){
|
|
static long oldnum=0;
|
|
static unsigned long bcd=0;
|
|
|
|
if (num > 99999999) {
|
|
lcd_string("overflow");
|
|
return;
|
|
}
|
|
|
|
/* This conversion takes too long at 32kHz, so we cache the last
|
|
value for rendering. */
|
|
if(oldnum==num){
|
|
lcd_hex(bcd);
|
|
return;
|
|
}
|
|
|
|
oldnum = num;
|
|
bcd = l2bcd(num);
|
|
lcd_hex(bcd);
|
|
}
|
|
|
|
|
|
//! Draws a decimal number on the screen.
|
|
void lcd_number(long num){
|
|
if(num<0){
|
|
lcd_unumber(0-num);
|
|
lcd_char(7,'-');
|
|
}else{
|
|
lcd_unumber(num);
|
|
}
|
|
}
|
|
|
|
//! Draws hex on the screen.
|
|
void lcd_hex(long num){
|
|
/* So in an ideal world, we'd have characters arranged nicely into
|
|
LCDM[] bytes as some development tools do, but in the real world,
|
|
we're pretty much stuck with them as they are physically
|
|
arranged.
|
|
|
|
This function takes a buffer of eight hex characters and displays
|
|
them on the screen.
|
|
*/
|
|
int i;
|
|
|
|
|
|
for(i=0;i<8;i++)
|
|
lcd_digit(i,(num>>(4*i))&0xf);
|
|
}
|
|
|
|
//! Activates a period, or turns it off.
|
|
void setperiod(int digit, int on){
|
|
if(on) //On
|
|
DRAWPOINT(lcdmap[digit][7]);
|
|
else //Off
|
|
CLEARPOINT(lcdmap[digit][7]);
|
|
}
|
|
|
|
//! Zeroes all the periods.
|
|
void clearperiods(){
|
|
int i;
|
|
for(i=0; i<8; i++)
|
|
setperiod(i,0);
|
|
}
|
|
|
|
|
|
//! Activates the colon. 2 for invert.
|
|
void setcolon(int on){
|
|
if(on==2) //Blink
|
|
lcdm[3]^=0x20;
|
|
else if(on==1) //On
|
|
lcdm[3]|=0x20;
|
|
else //Off
|
|
lcdm[3]&=~0x20;
|
|
}
|
|
|
|
//! Activates the am. 2 for invert.
|
|
void setam(int on){
|
|
if(on==2) //Blink
|
|
lcdm[0]^=0x04;
|
|
else if(on==1) //On
|
|
lcdm[0]|=0x04;
|
|
else //Off
|
|
lcdm[0]&=~0x04;
|
|
}
|
|
|
|
//! Activates the pm. 2 for invert.
|
|
void setpm(int on){
|
|
if(on==2) //Blink
|
|
lcdm[1]^=0x40;
|
|
else if(on==1) //On
|
|
lcdm[1]|=0x40;
|
|
else //Off
|
|
lcdm[1]&=~0x40;
|
|
}
|
|
|
|
//! Activates the mult sign. 2 for invert.
|
|
void setmult(int on){
|
|
if(on==2) //Blink
|
|
lcdm[4]^=0x40;
|
|
else if(on==1) //On
|
|
lcdm[4]|=0x40;
|
|
else //Off
|
|
lcdm[4]&=~0x40;
|
|
}
|
|
|
|
//! Activates the minus sign. 2 for invert.
|
|
void setminus(int on){
|
|
if(on==2) //Blink
|
|
lcdm[6]^=0x04;
|
|
else if(on==1) //On
|
|
lcdm[6]|=0x04;
|
|
else //Off
|
|
lcdm[6]&=~0x04;
|
|
}
|
|
|
|
//! Activates the plus sign. 2 for invert.
|
|
void setplus(int on){
|
|
if(on==2) //Blink
|
|
lcdm[7]^=0x40;
|
|
else if(on==1) //On
|
|
lcdm[7]|=0x40;
|
|
else //Off
|
|
lcdm[7]&=~0x40;
|
|
}
|
|
|
|
//! Activates the divide sign. 2 for invert.
|
|
void setdivide(int on){
|
|
if(on==2) //Blink
|
|
lcdm[0xc]^=0x04;
|
|
else if(on==1) //On
|
|
lcdm[0xc]|=0x04;
|
|
else //Off
|
|
lcdm[0xc]&=~0x04;
|
|
}
|
|
|
|
|