Initial pass on implementing ANSI escape sequences

Signed-off-by: Collin J. Doering <collin.doering@rekahsoft.ca>
This commit is contained in:
Collin J. Doering 2015-10-19 05:04:53 -04:00
parent f7893b7f88
commit d63c250630
3 changed files with 301 additions and 1 deletions

187
lcdLib.c
View File

@ -249,9 +249,112 @@ void writeCharToLCD(char c) {
}
}
/*
Given a character string, and a uint8_t pointer, reads the character string until a
non-numerical ASCII character, returning the integer representation of the number read. At
the end of the functions execution, the found_num uint8_t pointer will indicate how many
digits were read.
*/
uint8_t readASCIINumber(const char* str, uint8_t* found_num) {
const uint8_t num_digits = 4;
uint8_t nums[num_digits];
while (*str != '\0' && *found_num < num_digits - 1) {
if (*str >= 0x30 && *str <= 0x39) {
// Use *str as a number (specified in ASCII)
nums[*(found_num++)] = *str - 0x30;
} else {
break;
}
str++;
}
uint8_t ret = 0;
for (uint8_t i = 0; i < num_digits; i++)
ret += nums[num_digits - i] * pow(10, i);
return ret;
}
void writeStringToLCD(const char* str) {
while (*str != '\0') {
writeCharToLCD(*str);
// Check for ANSI CSI (Control Sequence Introducer)
if (*str == '\e') {
if (*(++str) != '\0' && *str == '[') {
// Read optional variable length number in ASCII (0x30 - 0x3f) where 0x3a - 0x3f are
// ignored (they are used as flags by some terminals
uint8_t fnd0;
uint8_t num0 = readASCIINumber(str++, &fnd0);
// Read optional (semicolon followed by optional variable length number)
uint8_t fnd1;
uint8_t num1;
if (*(++str) != '\0' && *str == ';') {
num1 = readASCIINumber(str++, &fnd1);
// Read control character (between 0x40 - 0x7e) for two argument sequences
switch (*str) {
case 'f': // HVP - Horizontal and vertical position
case 'H': // CUP - Cursor position
num0 = fnd0 ? num0 : 1;
num1 = fnd1 ? num1 : 1;
setCursorPosition(num0, num1);
break;
;;
default: // Invalid control character
break;
;;
}
} else if (*str != '\0') {
// Read control character (between 0x40 - 0x7e) for single argument sequences
switch (*str) {
case 'A': // CUU - Cursor up
num0 = fnd0 ? num0 : 1;
moveCursorUp(num0);
break;
;;
case 'B': // CUD - Cursor down
num0 = fnd0 ? num0 : 1;
moveCursorDown(num0);
break;
;;
case 'C': // CUF - Cursor forward
num0 = fnd0 ? num0 : 1;
moveCursorForward(num0);
break;
;;
case 'D': // CUB - Cursor back
num0 = fnd0 ? num0 : 1;
moveCursorBackward(num0);
break;
;;
case 'E': // CNL - Cursor next line
num0 = fnd0 ? num0 : 1;
moveCursorNextLine(num0);
break;
;;
case 'F': // CPL - Cursor previous line
num0 = fnd0 ? num0 : 1;
moveCursorPreviousLine(num0);
break;
;;
case 'G': // CHA - Cursor horizontal absolute
num0 = fnd0 ? num0 : 1;
moveCursorToColumn(num0);
break;
;;
default: // Invalid control character
break;
;;
}
} else {
return; // Invalid escape sequence (terminated early)
}
}
} else {
writeCharToLCD(*str);
}
str++;
}
}
@ -280,6 +383,88 @@ void returnHome(void) {
currentLineChars = 0;
}
void getCursorPosition(uint8_t* row, uint8_t* column) {
*row = currentLineNum + 1;
*column = currentLineChars + 1;
}
void setCursorPosition(uint8_t row, uint8_t column) {
// Set currentLineNum and currentLineChars
currentLineNum = row ? row - 1 : 0;
currentLineChars = column ? column - 1 : 0;
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorUp(uint8_t n) {
if (n < currentLineNum + 1) {
currentLineNum -= n;
} else {
currentLineNum = 0;
}
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorDown(uint8_t n) {
if (n + currentLineNum > LCD_NUMBER_OF_LINES - 1) {
currentLineNum += n;
} else {
currentLineNum = LCD_NUMBER_OF_LINES - 1;
}
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorForward(uint8_t n) {
if (n + currentLineChars > LCD_CHARACTERS_PER_LINE - 1) {
currentLineChars += n;
} else {
currentLineChars = LCD_CHARACTERS_PER_LINE - 1;
}
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorBackward(uint8_t n) {
if (n < currentLineChars + 1) {
currentLineChars += n;
} else {
currentLineChars = 0;
}
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorNextLine(uint8_t n) {
if (n + currentLineNum > LCD_NUMBER_OF_LINES - 1) {
currentLineNum += n;
} else {
currentLineNum = LCD_NUMBER_OF_LINES - 1;
}
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorPreviousLine(uint8_t n) {
if (n < currentLineNum + 1) {
currentLineNum -= n;
} else {
currentLineNum = 0;
}
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
}
void moveCursorToColumn(uint8_t n) {
if (n < LCD_CHARACTERS_PER_LINE) {
currentLineChars = n ? n - 1 : 0;
writeLCDInstr(INSTR_DDRAM_ADDR | (lineBeginnings[currentLineNum] + currentLineChars));
} // else index out of range (off screen column)
}
//-----------------------------------------------------------------------------------------------
/* char readCharFromLCD(void) { */
/* loop_until_LCD_BF_clear(); // Wait until LCD is ready for new instructions */

View File

@ -25,6 +25,7 @@
// Includes -------------------------------------------------------------------------------
#include <avr/io.h>
#include <math.h>
#include "lcdLibConfig.h"
//------------------------------------------------------------------------------------------
@ -65,6 +66,11 @@
// Set DD RAM address instruction
#define INSTR_DDRAM_ADDR 0x80
//-------------------------------------
#define LCD_CHARACTERS_PER_SCREEN (LCD_CHARACTERS_PER_LINE * LCD_NUMBER_OF_LINES)
//------------------------------------
// Function definitions
@ -133,6 +139,9 @@ void writeCharToLCD(char);
*/
void writeStringToLCD(const char*);
//-----------------------------------------------------------------------------------------------
// LCD command functions
/**
Clears the display and positions the cursor in the top left of the LCD screen.
*/
@ -143,11 +152,60 @@ void clearDisplay(void);
*/
void returnHome(void);
/**
Gets the current row and column of the LCD cursor.
*/
void getCursorPosition(uint8_t* row, uint8_t* column);
/**
Sets given pointers row and column to the current row and column occupied by the LCD cursor.
*/
void setCursorPosition(uint8_t row, uint8_t column);
/**
Moves the cursor n positions up. If the cursor is at the edge of the screen this has no effect.
*/
void moveCursorUp(uint8_t n);
/**
Moves the cursor n positions down. If the cursor is at the edge of the screen this has no effect.
*/
void moveCursorDown(uint8_t n);
/**
Moves the cursor n positions forward. If the cursor is at the edge of the screen this has no effect.
*/
void moveCursorForward(uint8_t n);
/**
Moves the cursor n positions backwards. If the cursor is at the edge of the screen this has no effect.
*/
void moveCursorBackward(uint8_t n);
/**
Moves the cursor to the beginning of the line n lines down.
*/
void moveCursorNextLine(uint8_t n);
/**
Moves the cursor to the beginning of the line n lines up.
*/
void moveCursorPreviousLine(uint8_t n);
/**
Moves the cursor to column n. If n is off screen go to the last line.
*/
void moveCursorToColumn(uint8_t n);
//-----------------------------------------------------------------------------------------------
/*
UNIMPLEMENTED
*/
char readCharFromLCD(void);
//-----------------------------------------------------------------------------------------------
/**
Initialize the LCD display via software initialization as specified by the datasheet.
*/

View File

@ -29,6 +29,7 @@
#include <avr/interrupt.h>
#include <avr/power.h>
#include <util/delay.h>
#include <stdlib.h>
#include "lcdLib.h"
#include "ansi_escapes.h"
@ -38,6 +39,8 @@
#define STATUS_LED_DDR DDRC
#define STATUS_LED PC5
//--------------------------------------------------
void flashLED(uint8_t times) {
while (times > 0) {
STATUS_LED_PORT |= 1 << STATUS_LED; // turn on status LED
@ -47,12 +50,27 @@ void flashLED(uint8_t times) {
times--;
}
}
//--------------------------------------------------
/*
Initialize previous, current, and next screen variables to spaces
*/
char* initScreenMem(const uint8_t len) {
char *scrn = (char*) malloc(len * sizeof(char));
for (uint8_t i = 0; i < len; i++) {
scrn[i] = ' ';
}
return scrn;
}
int main(void) {
clock_prescale_set(clock_div_1);
STATUS_LED_DDR |= 1 << STATUS_LED; // DEBUG
// Allocate and init first block of heap for storing LCD data
char* scrn = initScreenMem(LCD_CHARACTERS_PER_SCREEN);
initUSART();
char serialChar;
@ -60,6 +78,45 @@ int main(void) {
//initLCDByInternalReset();
flashLED(5); // DEBUG
writeStringToLCD("Backwards 4" CUB(4));
_delay_ms(5000);
clearDisplay();
writeStringToLCD("Backwards 3" CUB(3));
_delay_ms(5000);
clearDisplay();
writeStringToLCD("Backwards 2" CUB(2));
_delay_ms(5000);
clearDisplay();
writeStringToLCD("Backwards 1" CUB(1));
_delay_ms(5000);
clearDisplay();
writeStringToLCD("Forwards 4" CUF(4));
_delay_ms(5000);
/* writeStringToLCD(CNL(1)); */
/* _delay_ms(5000); */
/* writeStringToLCD(CUF(10)); */
/* _delay_ms(5000); */
/* writeStringToLCD(CPL(1)); */
/* _delay_ms(5000); */
/* writeStringToLCD(CHA(20)); */
/* _delay_ms(5000); */
/* writeStringToLCD(CUP(20,20)); */
/* _delay_ms(5000); */
/* writeStringToLCD(CUP(1,1)); */
/* _delay_ms(5000); */
while (1) {
serialChar = receiveByte();