/* -*- c -*- */
/* Code for driving the lcd on the HPA449 */
/* HPA449 LCD config:
- Segment 0 used for turning off unused segments. Normally off.
- Antenna and alpha digit 7 tied to S1. Normally off.
- Segs 2-11, 16-35 connected to elements.
- Segs 12-15 switched between seg 0 or certain elements.
- Segs 36-39 used for SPI only, not available for LCD.
See also lcdmap.txt
*/
#include "sysconf.h"
typedef struct seginfo
{
volatile char *loc;
unsigned char mask;
} seginfo;
/* ----- BEGIN THEFT ----- */
/* THEFT ALERT: stolen from 'demo.c' by Rowley & Assoc. */
// Starburst segment definitions.
#define _N 0x0001
#define _M 0x0002
#define _K 0x0004
#define _J 0x0008
#define _D 0x0010
#define _C 0x0020
#define _B 0x0040
#define _A 0x0080
#define _P 0x0100
#define _Q 0x0200
#define _G 0x0400
#define _H 0x0800
#define _E 0x2000
#define _F 0x4000
static const u16 starburst_segments[] =
{
/* */ 0,
/*!*/ _F | _E, // Lame
/*"*/ _H | _K,
/*#*/ _J | _B | _P | _C | _G | _M,
/*$*/ _A | _F | _G | _M | _C | _D | _J | _P,
/*%*/ 0, // No good idea
/*&*/ 0, // No good idea
/*'*/ _K,
/*(*/ _A | _F | _E | _D,
/*)*/ _A | _B | _C | _D,
/***/ _H | _J | _K | _G | _M | _Q | _P | _N,
/*+*/ _J | _G | _M | _P,
/*,*/ 0, // No good idea
/*-*/ _G | _M,
/*.*/ 0, // Should use decimal point, but...
/*/*/ _K | _Q,
/*0*/ _A | _B | _C | _D | _E | _F | _Q | _K,
/*1*/ _C | _B,
/*2*/ _A | _B | _M | _G | _E | _D,
/*3*/ _A | _B | _M | _G | _C | _D,
/*4*/ _F | _G | _M | _B | _C,
/*5*/ _A | _F | _G | _M | _C | _D,
/*6*/ _A | _F | _E | _D | _C | _M | _G,
/*7*/ _F | _A | _B | _C,
/*8*/ _A | _B | _C | _D | _E | _F | _G | _M,
/*9*/ _A | _F | _G | _M | _B | _C | _D,
/*:*/ 0, // No good idea
/*;*/ 0, // No good idea
/*<*/ _K | _N,
/*=*/ _G | _M | _D,
/*>*/ _H | _Q,
/*?*/ _A | _B | _M | _G | _E,
/*@*/ 0, // No good idea
/*A*/ _E | _F | _A | _B | _C | _G | _M,
/*B*/ _A | _B | _C | _D | _J | _P | _M,
/*C*/ _A | _F | _E | _D,
/*D*/ _A | _B | _C | _D | _J | _P,
/*E*/ _A | _F | _E | _D | _G | _M,
/*F*/ _A | _F | _E | _G | _M,
/*G*/ _A | _F | _E | _D | _C | _M,
/*H*/ _F | _E | _G | _M | _B | _C,
/*I*/ _A | _J | _P | _D,
/*J*/ _B | _C | _D | _E,
/*K*/ _F | _E | _G | _K | _N,
/*L*/ _F | _E | _D,
/*M*/ _E | _F | _H | _K | _B | _C,
/*N*/ _E | _F | _H | _N | _C | _B,
/*O*/ _A | _B | _C | _D | _E | _F,
/*P*/ _E | _F | _A | _B | _G | _M,
/*Q*/ _A | _B | _C | _D | _E | _F | _N,
/*R*/ _E | _F | _A | _B | _G | _M | _N,
/*S*/ _A | _F | _G | _M | _C | _D,
/*T*/ _A | _J | _P,
/*U*/ _F | _E | _D | _C | _B,
/*V*/ _F | _E | _Q | _K,
/*W*/ _F | _E | _Q | _N | _C | _B,
/*X*/ _H | _K | _Q | _N,
/*Y*/ _H | _K | _P,
/*Z*/ _A | _K | _Q | _D
};
/* ----- END THEFT ----- */
#if 1
static const seginfo bargraphtbl[]={
{&LCDM7,(1<<2)},
{&LCDM7,(1<<1)},
{&LCDM7,1},
{&LCDM7,(1<<4)},
{&LCDM7,(1<<5)},
{&LCDM7,(1<<6)},
{&LCDM7,(1<<7)},
{&LCDM8,(1<<3)},
{&LCDM8,(1<<2)},
{&LCDM8,(1<<1)}
};
static const u16 bgcentretbl[]={
0xfc1,0xbc1,0x9c1,0x8c1,0x841,0x861,0x821,0x831,0x839,0x83d,0x83f
};
static const u16 bglrtbl[]={
0x801,0xc01,0xe01,0xf01,0xf81,0xfc1,0xfe1,0xff1,0xff9,0xffd,0xfff
};
static const u16 bgonedottbl[]={
0x801,0xc01,0xa01,0x901,0x881,0x841,0x821,0x811,0x809,0x805,0x803,0x801
};
#endif
static const seginfo lgcolontbl[]={
{&LCDM16,(1<<7)},
{&LCDM14,(1<<7)},
{&LCDM12,(1<<7)},
{&LCDM10,(1<<7)},
{&LCDM8,(1<<7)}
};
static const seginfo lgdptbl[]={
{&LCDM16,(1<<4)},
{&LCDM14,(1<<4)},
{&LCDM12,(1<<4)},
{&LCDM10,(1<<4)},
{&LCDM8,(1<<4)},
{&LCDM2,(1<<4)}
};
static const seginfo smdptbl[]={
{&LCDM6,1<<3},
{&LCDM5,1<<3},
{&LCDM3,1<<7}
};
/* charset format: pabcdefg */
static const unsigned char segtbl[]={
// punctuation, 0x20-0x2f
//' ' ! " # $ % & ' ( ) * + , - . /
0,0xa0,0x22,0,0,0,0,0x02,0x4e,0x78,0x49,0x31,0,1,0x80,0,
// numbers: 0x30-0x39
//0 1 2 3 4 5 6 7 8 9
0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b,
// extra stuff, 0x3a-0x40
// : ; < = > ? @
0,0,0,9,0,0xe5,0,
// letters, 0x41-0x59
//a b c d e f g h
0x7d,0x1f,0x0d,0x3d,0x6f,0x47,0x5e,0x17,
//i j k l m n o p
0x10,0x3c,0x0f,0x0e,0x6a,0x15,0x1d,0x67,
//q r s t u v w x
0x73,0x05,0x1b,0x07,0x1c,0x5c,0x2b,0x25,
//y z
0x3b,0x65
};
// listing order: gfedcba
static const seginfo smsegtbl[]={
// digit 0 (8)
{&LCDM6,(1<<5)},
{&LCDM6,(1<<4)},
{&LCDM6,(1<<6)},
{&LCDM6,(1<<7)},
{&LCDM6,(1<<2)},
{&LCDM6,(1<<1)},
{&LCDM6,1},
// digit 1 (9)
{&LCDM5,(1<<5)},
{&LCDM5,(1<<4)},
{&LCDM5,(1<<6)},
{&LCDM5,(1<<7)},
{&LCDM5,(1<<2)},
{&LCDM5,(1<<1)},
{&LCDM5,1},
// digit 2 (10)
{&LCDM4,(1<<1)},
{&LCDM4,(1<<5)},
{&LCDM4,(1<<6)},
{&LCDM4,(1<<3)},
{&LCDM4,(1<<2)},
{&LCDM4,1},
{&LCDM4,(1<<4)},
// digit 3 (11)
{&LCDM3,(1<<1)},
{&LCDM3,(1<<5)},
{&LCDM3,(1<<6)},
{&LCDM3,(1<<3)},
{&LCDM3,(1<<2)},
{&LCDM3,1},
{&LCDM3,(1<<4)}
};
void sblcd_seg_set(const seginfo *si, int on);
// This LCD init turns all segments off.
void sblcd_init(void)
{
int i;
volatile char *volatile mp=&LCDM1;
//BTCTL=0010 1000
BTCTL=0x28;
for (i=0;i<20;++i) {
*mp=0;
++mp;
}
//lcdctl=1101 1101
LCDCTL=0xdd;
P5SEL|=0x4;
P5SEL|=0x8;
P5SEL|=0x10;
P5SEL|=0x2;
P5SEL|=0x1;
P4SEL|=0x80;
P4SEL|=0x40;
P5SEL|=0x80;
P5SEL|=0x40;
P5SEL|=0x20;
}
void sblcd_lg_showc(char c, int position)
{
volatile char *base;
u16 digits;
if (position<0) return;
if (position>5) return;
if (c<' ') return;
if (c>='a'&&c<='z')
c-=0x20;
if (c>'Z') return;
base=&LCDM17 - position*2;
digits=starburst_segments[c-32];
base[0] = digits;
base[1] = (digits>>8)|(base[1]&0x90);
}
void sblcd_SEG_SET(volatile char *loc, u8 mask, int on)
{
if (on)
sblcd_SEG_ON((volatile char *)loc,mask);
else
sblcd_SEG_OFF((volatile char *)loc,mask);
}
void sblcd_seg_set(const seginfo *si, int on)
{
if (on)
sblcd_seg_on(si);
else
sblcd_seg_off(si);
}
void sblcd_lg_dp_set(int ind, int on)
{
--ind;
if (ind<0) return;
if (ind>=6) return;
if (ind>=5) return;
sblcd_seg_set(&(lgdptbl[ind]),on);
}
void sblcd_lg_colon_set(int ind, int on)
{
--ind;
if (ind<0) return;
if (ind>=5) return;
if (ind>=5) return;
sblcd_seg_set(&(lgcolontbl[ind]),on);
}
void sblcd_lg_alldpcolonoff(void)
{
int i;
for (i=1;i<7;++i) {
sblcd_lg_colon_off(i);
sblcd_lg_dp_off(i);
}
}
/* Shows a string on the alpha portion of the HPA449's LCD */
void sblcd_lg_showstr(char *c)
{
int i,blank=0;
if (*c=='+') {
sblcd_plus_on();
sblcd_minus_off();
c++;
} else if (*c=='-') {
sblcd_minus_on();
sblcd_plus_off();
c++;
} else {
sblcd_minus_off();
sblcd_plus_off();
}
sblcd_lg_alldpcolonoff();
for (i=0;i<6;++i) {
if (!blank)
if (!*c)
blank=1;
if (blank)
sblcd_lg_showc(' ',i);
else {
if (*c=='.') {
sblcd_lg_dp_on(i);
sblcd_lg_colon_off(i);
--i;
} else if (*c==':') {
sblcd_lg_colon_on(i);
sblcd_lg_dp_off(i);
--i;
} else {
sblcd_lg_showc(*c,i);
}
++c;
}
}
}
#if 1
// ---- bargraph display ----------------------------------------------
void sblcd_bg_set(u16 segs)
{
int i;
sblcd_SEG_SET(sblcd_SEG_BGR,segs&1);
sblcd_SEG_SET(sblcd_SEG_BGL,segs&(1<<11));
for (i=9;i>=0;--i){
segs=segs>>1;
sblcd_seg_set(&bargraphtbl[i],segs&1);
}
}
void sblcd_bg_centre(int val)
{
val+=5;
if (val<0) val=0;
if (val>10) val=10;
sblcd_bg_set(bgcentretbl[val]);
}
void sblcd_bg_onedot(int val)
{
if (val<0) val=0;
if (val>11) val=11;
sblcd_bg_set(bgonedottbl[val]);
}
void sblcd_bg_lr(int val)
{
if (val<0) val=0;
if (val>10) val=10;
sblcd_bg_set(bglrtbl[val]);
}
#endif
// ---- small 7-seg display ----------------------------------------------
unsigned char chrtosegs(char c)
{
if (c>=