/*
AS1107.cpp - Library for interfacing the AS1107 LED Driver Chip
Created by Stephan Elsner, March 29, 2011
Scrolltext uses a proportional character font
Tested with Arduino Duemilenove
version 0.82
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <avr/pgmspace.h>
#include "WProgram.h"
#include "AS1107.h"
const byte AS1107::_repcharoff = 27;
// Font Data
PROGMEM prog_uchar _font[] = {
// -------- Space
0b00000000,
0b00000000,
0b00000000,
0b00000000,
// -------- A
0b01111110,
0b10010000,
0b10010000,
0b01111110,
// -------- B
0b01101100,
0b10010010,
0b10010010,
0b11111110,
// -------- C
0b10000010,
0b10000010,
0b01111100,
// -------- D
0b00111000,
0b01000100,
0b10000010,
0b11111110,
// -------- E
0b10000010,
0b10010010,
0b11111110,
// -------- F
0b10000000,
0b10010000,
0b11111110,
// -------- G
0b01011100,
0b10010010,
0b10000010,
0b01111100,
// -------- H
0b11111110,
0b00010000,
0b00010000,
0b11111110,
// -------- I
0b10000010,
0b11111110,
0b10000010,
// -------- J
0b11111100,
0b00000010,
0b00001100,
// -------- K
0b10000110,
0b01001000,
0b00110000,
0b11111110,
// -------- L
0b00000010,
0b00000010,
0b11111110,
// -------- M
0b11111110,
0b01100000,
0b00111100,
0b01100000,
0b11111110,
// -------- N
0b11111110,
0b00011000,
0b01100000,
0b11111110,
// -------- O
0b01111100,
0b10000010,
0b10000010,
0b01111100,
// -------- P
0b01100000,
0b10010000,
0b10010000,
0b11111110,
// -------- Q
0b01111010,
0b10000100,
0b10001010,
0b01111100,
// -------- R
0b01100110,
0b10011000,
0b10010000,
0b11111110,
// -------- S
0b10001100,
0b10010010,
0b01100010,
// -------- T
0b10000000,
0b11111110,
0b10000000,
// -------- U
0b11111100,
0b00000010,
0b00000010,
0b11111100,
// -------- V
0b11000000,
0b00111000,
0b00000110,
0b00111000,
0b11000000,
// -------- W
0b11111110,
0b00001100,
0b00111000,
0b00001100,
0b11111110,
// -------- X
0b11000110,
0b00111000,
0b00111000,
0b11000110,
// -------- Y
0b11100000,
0b00011110,
0b11100000,
// -------- Z
0b11000010,
0b10110010,
0b10001110,
// -------- Unknown character
0b00111000,
0b00111000,
0b00111000,
// -------- 0
0b01111100,
0b10100010,
0b10010010,
0b01111100,
// -------- 1
0b11111110,
0b01000000,
// -------- 2
0b01100010,
0b10010010,
0b10001110,
// -------- 3
0b01101100,
0b10010010,
0b10000010,
// -------- 4
0b11111110,
0b00010000,
0b11110000,
// -------- 5
0b10001100,
0b10010010,
0b11110010,
// -------- 6
0b01001100,
0b10010010,
0b10010010,
0b01111100,
// -------- 7
0b11100000,
0b10011110,
0b10000000,
// -------- 8
0b01101100,
0b10010010,
0b10010010,
0b01101100,
// -------- 9
0b01111100,
0b10010010,
0b10010010,
0b01100100,
// -------- :
0b00100100,
// -------- ;
0b00100110,
0b00000001,
// -------- !
0b01100000,
0b11111010,
0b01100000,
// -------- Heart
0b01111000,
0b11111100,
0b11111110,
0b01111111,
0b11111110,
0b11111100,
0b01111000,
// -------- <
0b01000100,
0b00101000,
0b00010000,
// -------- =
0b00101000,
0b00101000,
0b00101000,
0b00101000,
// -------- >
0b00010000,
0b00101000,
0b01000100,
// -------- ?
0b01100000,
0b10011010,
0b10000000,
// -------- @
0b01111100,
0b10000010,
0b10111010,
0b10100010,
0b01011100,
// -------- (
0b10000010,
0b01111100,
// -------- )
0b01111100,
0b10000010,
// -------- *
0b00101000,
0b00010000,
0b00101000,
// -------- +
0b00010000,
0b00010000,
0b01111100,
0b00010000,
0b00010000,
// -------- ,
0b00000110,
0b00000001,
// -------- -
0b00010000,
0b00010000,
0b00010000,
0b00010000,
// -------- .
0b00000010,
// -------- /
0b11000000,
0b00111000,
0b00000110,
// -------- a
0b00111110,
0b00100010,
0b00100010,
0b00011100,
// -------- b
0b00011100,
0b00100010,
0b00100010,
0b11111110,
// -------- c
0b00100010,
0b00100010,
0b00011100,
// -------- d
0b11111110,
0b00100010,
0b00100010,
0b00011100,
// -------- e
0b00011000,
0b00101010,
0b00101010,
0b00011100,
// -------- f
0b10010000,
0b01111110,
0b00010000,
// -------- g
0b00111110,
0b00100101,
0b00100101,
0b00011000,
// -------- h
0b00011110,
0b00100000,
0b00100000,
0b11111110,
// -------- i
0b00000010,
0b01011110,
0b00010010,
// -------- j
0b01011110,
0b00000001,
0b00000001,
// -------- k
0b00100010,
0b00010100,
0b00001000,
0b11111110,
// -------- l
0b00000010,
0b11111100,
// -------- m
0b00011110,
0b00100000,
0b00111110,
0b00100000,
0b00111110,
// -------- n
0b00011110,
0b00100000,
0b00100000,
0b00111110,
// -------- o
0b00011100,
0b00100010,
0b00100010,
0b00011100,
// -------- p
0b00011100,
0b00100010,
0b00100010,
0b00111111,
// -------- q
0b00111111,
0b00100010,
0b00100010,
0b00011100,
// -------- r
0b00010000,
0b00100000,
0b00111110,
// -------- s
0b00100100,
0b00101010,
0b00101010,
0b00010010,
// -------- t
0b00100010,
0b11111100,
0b00100000,
// -------- u
0b00111110,
0b00000010,
0b00000010,
0b00111100,
// -------- v
0b00111000,
0b00000110,
0b00111000,
// -------- w
0b00111110,
0b00000010,
0b00011110,
0b00000010,
0b00111100,
// -------- x
0b00110110,
0b00001000,
0b00110110,
// -------- y
0b00111110,
0b00000101,
0b00000101,
0b00111001,
// -------- z
0b00110010,
0b00101010,
0b00100110,
0b00100010,
0b11000001
};
// Char width table
PROGMEM prog_uchar _charwidth[] = {4,4,4,3,4,3,3,4,4,3,3,4,3,5,4,4,4,4,4,3,3,4,5,5,4,3,3,
3,4,2,3,3,3,3,4,3,4,4,1,2,3,7,3,4,3,3,5,2,2,3,5,2,4,1,3,
4,4,3,4,4,3,4,4,3,3,4,2,5,4,4,4,4,3,4,3,4,3,5,3,4,4,0 };
// ASCII Codes of the implemented characters
PROGMEM prog_uchar _charcodes[] = {32,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,255,48,49,50,51,52,53,
54,55,56,57,58,59,33,3,60,61,62,63,64,40,41,42,43,44,
45,46,47,97,98,99,100,101,102,103,104,105,106,107,108,
109,110,111,112,113,114,115,116,117,118,119,120,121,
122,0};
// ------------------------------------------------------------------------------------
// Constructor, initialize arduino
AS1107::AS1107(byte cspin, byte clkpin, byte datapin)
{
_cspin = cspin;
_clkpin = clkpin;
_datapin = datapin;
pinMode(cspin, OUTPUT);
pinMode(clkpin, OUTPUT);
pinMode(datapin, OUTPUT);
digitalWrite(cspin,HIGH);
digitalWrite(clkpin,LOW);
digitalWrite(datapin,LOW);
}
// ------------------------------------------------------------------------------------
// Initializes Arduino and AS1107
// buffer is the initial screen buffer
void AS1107::Init(byte * buffer)
{
_buffer = buffer;
CalculateCharOffsets();
// Clear Screen buffer
Clear();
for (int i=0; i<=HighestCtrlNum; i++) {
WriteRegister(i, Registers::Shutdown, ShutdownModes::Normal);
WriteRegister(i, Registers::DecodeMode, 0x00);
WriteRegister(i, Registers::IntensityControl, 0x00);
WriteRegister(i, Registers::ScanLimit, 0x07);
}
}
// ------------------------------------------------------------------------------------
// Set the Screen buffer
void AS1107::SetBuffer(byte * buffer)
{
_buffer = buffer;
}
// ------------------------------------------------------------------------------------
// Writes Data to a Register of the AS1106/AS1107
// chip: Number of the controller chip (starting at 0 for the left)
// reg: Register of the controller
// data: Data to be written
void AS1107::WriteRegister( byte chip, byte reg, byte data)
{
if (chip>=0 && chip <= HighestCtrlNum) {
chip = HighestCtrlNum -chip;
digitalWrite(_cspin,LOW);
for (int i=0; i<=HighestCtrlNum; i++) {
if (i == chip) {
shiftOut(_datapin, _clkpin, MSBFIRST, reg);
shiftOut(_datapin, _clkpin, MSBFIRST, data);
}
else {
shiftOut(_datapin, _clkpin, MSBFIRST, Registers::NoOp);
shiftOut(_datapin, _clkpin, MSBFIRST, 0);
}
}
digitalWrite(_cspin,HIGH);
}
}
// ------------------------------------------------------------------------------------
// Writes a column of data to the LED-Matrix
// column: column number, starting at 0
// data : screen data to be written
void AS1107::WriteColumn( byte column, byte data)
{
// if you use unusual matrix row wiring, you can manipulate data here
byte chip = (column) >>3;
byte reg = (column % 8) +1;
WriteRegister(chip, reg, data);
}
// ------------------------------------------------------------------------------------
// Sets the status of a LED in the screen buffer
void AS1107::SetLed(int x, int y, byte value)
{
if (x<=Maxx && y<=Maxy && x>=0 && y>=0) {
if (value>0) value = 1;
SetLedInternal(x, y, value);
}
}
// ------------------------------------------------------------------------------------
// Writes Buffer to Screen
// needs to be called after a graphics operation to see anything
void AS1107::Update()
{
for (byte i=0; i<=Maxx; i++) {
WriteColumn(i, _buffer[i]);
}
}
// ------------------------------------------------------------------------------------
// Clear the Screen Buffer
void AS1107::Clear()
{
for (byte i=0; i<=Maxx; _buffer[i++]=0);
}
// ------------------------------------------------------------------------------------
// Shift the content of the Screen buffer to the left
void AS1107::ShiftLeft()
{
for (byte i=1; i<=Maxx; i++) {
_buffer[i-1] = _buffer[i];
}
_buffer[Maxx] = 0;
}
// ------------------------------------------------------------------------------------
// Shift the content of the Screen buffer to the right
void AS1107::ShiftRight()
{
for (byte i=Maxx; i>=1; i--) {
_buffer[i] = _buffer[i-1];
}
_buffer[0] = 0;
}
// ------------------------------------------------------------------------------------
// Shift the content of the Screen buffer up
void AS1107::ShiftUp()
{
for (byte i=0; i<=Maxx; i++) {
_buffer[i] = _buffer[i]<<1 & 0xFE;
}
}
// ------------------------------------------------------------------------------------
// Shift the content of the Screen buffer up
void AS1107::ShiftUp(byte from, byte to)
{
for (byte i=from; i<=to; i++) {
_buffer[i] = _buffer[i]<<1 & 0xFE;
}
}
// ------------------------------------------------------------------------------------
// Shift the content of the Screen buffer down
void AS1107::ShiftDown()
{
for (byte i=0; i<=Maxx; i++) {
_buffer[i] = _buffer[i]>>1 & 0x7F;
}
}
// ------------------------------------------------------------------------------------
// Shift the content of the Screen buffer down
void AS1107::ShiftDown(byte from, byte to)
{
for (byte i=from; i<=to; i++) {
_buffer[i] = _buffer[i]>>1 & 0x7F;
}
}
// ------------------------------------------------------------------------------------
// draws a line from x0 ,y0 to x1,y1
void AS1107::DrawLine(int x0, int y0, int x1, int y1)
{
int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
int err = dx+dy, e2; /* error value e_xy */
for(;;){ /* loop */
SetLed(x0,y0,ON);
if (x0==x1 && y0==y1) break;
e2 = 2*err;
if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
}
}
// ------------------------------------------------------------------------------------
// draws a box from x0,x0 to x1,y1
void AS1107::DrawBox(int x0, int y0, int x1, int y1)
{
DrawLine(x0,y0,x1,y0);
DrawLine(x1,y0,x1,y1);
DrawLine(x1,y1,x0,y1);
DrawLine(x0,y1,x0,y0);
}
// ------------------------------------------------------------------------------------
// draws an ellipse
// center xm, ym - radius a,b
void AS1107::DrawEllipse(int xm, int ym, int a, int b)
{
if (a ==0 && b== 0) {
SetLed(xm,ym,ON);
return;
}
int dx = 0, dy = b; /* first quadrant from top left to bottom right */
int a2 = a*a, b2 = b*b;
int err = b2-(2*b-1)*a2, e2; /* error value in the first step */
do {
SetLed(xm+dx, ym+dy, ON); /* I. Quadrant */
SetLed(xm-dx, ym+dy, ON); /* II. Quadrant */
SetLed(xm-dx, ym-dy, ON); /* III. Quadrant */
SetLed(xm+dx, ym-dy, ON); /* IV. Quadrant */
e2 = 2*err;
if (e2 < (2*dx+1)*b2) { dx++; err += (2*dx+1)*b2; }
if (e2 > -(2*dy-1)*a2) { dy--; err -= (2*dy-1)*a2; }
} while (dy >= 0);
while (dx++ < a) { /* correction for flat ellipses (b=1) */
SetLed(xm+dx, ym, ON);
SetLed(xm-dx, ym, ON);
}
}
// ------------------------------------------------------------------------------------
// Writes Text at a screen position
void AS1107::DrawText (int x, int y, char *str)
{
byte count;
char thechar;
while (*str != '\0') {
Serial.println(*str,DEC);
x+=DrawChar(x, y, *str);
str++;
}
}
// ------------------------------------------------------------------------------------
// Draws a single character at a screen position
// returns the x-position for the next character
byte AS1107::DrawChar (int x, int y, char thechar)
{
y+=7;
byte charnum, colct, count=0, colbits;
int fontidx;
charnum = GetInternalCharCode(thechar);
// get the location of the first column of the font
fontidx = _charoffset[charnum]-1;
// get the width of the font
colct = pgm_read_byte_near(_charwidth + charnum);
for (byte i=colct; i>0; i--) {
colbits = pgm_read_byte_near(_font + fontidx + i);
for (byte j=0; j<=7; j++) {
if ((colbits >>j) & 1) {
SetLed(x, y-j, 1);
}
}
x++;
}
return colct+1;
}
// ------------------------------------------------------------------------------------
// Sets the Text for Scrolline
void AS1107::SetScrollText(char *string, int charspacing)
{
_charspacing = charspacing;
_outputstring = string;
_curchr = string;
_hastext = true;
_colct =-1;
}
// ------------------------------------------------------------------------------------
// Scrolls the text one pixel to the left
// returns true if last character has been displayed
boolean AS1107::TextScroll()
{
boolean lastchar = false;
byte colbits = 0;
if (_colct == (0-_charspacing-1)) {
lastchar = NextCharacter();
}
if (_colct>=0) {
colbits = pgm_read_byte_near(_font + _fontidx + _colct);
}
ShiftLeft();
_buffer[Maxx] = colbits;
Update();
_colct--;
return lastchar;
}
// ------------------------------------------------------------------------------------
// PRIVATE (Internal) functions
// ------------------------------------------------------------------------------------
// Set LED without Parameter check
void AS1107::SetLedInternal(byte x, byte y, byte value)
{
_buffer[x] |= value << (Maxy-y);
}
// ------------------------------------------------------------------------------------
// fetches the next character of the Scrollline
// returns true if string is at the end
boolean AS1107::NextCharacter()
{
boolean lastchar = false;
if (_hastext) {
char thechar = *_curchr;
boolean found = false;
byte charnum = 0;
byte i;
// if the string ends, start from the beginning
if (thechar == 0) {
lastchar = true;
_curchr = _outputstring;
thechar = *_curchr;
}
charnum = GetInternalCharCode(thechar);
// get the offset of the first column of the character
_fontidx = _charoffset[charnum];
// get the width of the font
_colct = pgm_read_byte_near(_charwidth + charnum) -1;
}
else {
_fontidx= _charoffset[_repcharoff];
_colct = pgm_read_byte_near(_charwidth + _repcharoff);
}
*_curchr++;
return lastchar;
}
// ------------------------------------------------------------------------------------
// calculates Character offsets from font width table in EEPROM
void AS1107::CalculateCharOffsets()
{
int off =0;
int idx=0;
int w=0;
int i=0;
do {
_charoffset[i]=off;
w = pgm_read_byte_near(_charwidth+i);
off += w;
i++;
} while (w != 0);
}
// ------------------------------------------------------------------------------------
// gets the character number of the built-in-font from the ASCII table
// returns number of the replacement character for unknown characters
byte AS1107::GetInternalCharCode(byte thechar)
{
int i=0;
int charnum;
do {
charnum = pgm_read_byte_near(_charcodes + i);
if (charnum == thechar) break;
i++;
} while (charnum != 0 );
if (charnum == 0) i = _repcharoff;
return i;
}