From 80f87d251309a7bbfe3502fee3594e56c6c61eba Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Thu, 25 Jun 2015 22:22:23 +0200 Subject: [PATCH] avr_firmware: WIP: UI and settings --- avr_firmware/Makefile | 7 +- avr_firmware/src/eeprom.h | 16 ++ avr_firmware/src/lcd.c | 44 +++++ avr_firmware/src/lcd.h | 8 + avr_firmware/src/main.c | 33 +--- avr_firmware/src/ui.c | 399 ++++++++++++++++++++++++++++++++++++++ avr_firmware/src/ui.h | 6 + 7 files changed, 487 insertions(+), 26 deletions(-) create mode 100644 avr_firmware/src/eeprom.h create mode 100644 avr_firmware/src/ui.c create mode 100644 avr_firmware/src/ui.h diff --git a/avr_firmware/Makefile b/avr_firmware/Makefile index 3b9cd5f..62ccf04 100644 --- a/avr_firmware/Makefile +++ b/avr_firmware/Makefile @@ -1,8 +1,11 @@ +GIT_VERSION := $(shell git describe --dirty=-d --always --tags --abbrev) + CC=avr-gcc #CCOPTS=-mmcu=atmega164a -std=c11 -flto -Os -ggdb -Wall -Wextra -pedantic -DF_CPU=8000000UL -CCOPTS=-mmcu=atmega32 -std=c11 -flto -Os -ggdb -mrelax -Wall -Wextra -pedantic -DF_CPU=8000000UL +CCOPTS=-mmcu=atmega32 -std=c11 -flto -Os -ggdb -mrelax -Wall -Wextra -Wno-char-subscripts -pedantic -DF_CPU=8000000UL -DVERSION=\"$(GIT_VERSION)\" -CCSRCS ::= uart.c main.c modem.c timer.c lcd.c + +CCSRCS ::= uart.c main.c modem.c timer.c lcd.c ui.c all: fw.elf diff --git a/avr_firmware/src/eeprom.h b/avr_firmware/src/eeprom.h new file mode 100644 index 0000000..e2f4097 --- /dev/null +++ b/avr_firmware/src/eeprom.h @@ -0,0 +1,16 @@ +#ifndef DMXGSM_AVR_EEPROM_H +#define DMXGSM_AVR_EEPROM_H + +#define EEPROM_SERIAL_OFS ((void*)1) +#define EEPROM_OSCCAL_OFS ((void*)0) +#define EEPROM_PIN_VALID_OFS ((void*)9) +#define EEPROM_PIN_OFS ((void*)10) +#define EEPROM_APN_VALID_OFS ((void*)14) +#define EEPROM_APN_OFS ((void*)15) +#define EEPROM_APN_USER_VALID_OFS ((void*)115) +#define EEPROM_APN_USER_OFS ((void*)116) +#define EEPROM_APN_PW_VALID_OFS ((void*)148) +#define EEPROM_APN_PW_OFS ((cvoid*)149) +#define EEPROM_EMPTY ((void*)181) + +#endif diff --git a/avr_firmware/src/lcd.c b/avr_firmware/src/lcd.c index ebfb8ca..539f7ab 100644 --- a/avr_firmware/src/lcd.c +++ b/avr_firmware/src/lcd.c @@ -71,6 +71,11 @@ void lcdWrite(bool rs, uint8_t data) _lcdWrite(rs, data); } +void lcdWriteChr(char chr) +{ + lcdWrite(true, (uint8_t)chr); +} + void lcdWriteStr(char const* str) { while (*str != '\0') @@ -84,6 +89,30 @@ void lcdWriteStrP(char const* str) lcdWrite(true, (uint8_t)c); } +void lcdWriteStrFill(char const* str) +{ + char cnt = 0; + while (*str != '\0') { + lcdWrite(true, (uint8_t)*str++); + ++cnt; + } + + for(;cnt < 20;++cnt) + lcdWrite(true, ' '); +} + +void lcdWriteStrFillP(char const* str) +{ + char c, cnt = 0; + while ((c = pgm_read_byte(str++)) != '\0') { + lcdWrite(true, (uint8_t)c); + ++cnt; + } + + for(;cnt < 20;++cnt) + lcdWrite(true, ' '); +} + static const uint8_t lineLUT[4] PROGMEM = {0x00, 0x40, 0x14, 0x54}; void lcdSetPos(unsigned char x, unsigned char y) @@ -92,6 +121,21 @@ void lcdSetPos(unsigned char x, unsigned char y) lcdWrite(false, 0x80 | adr); } +void lcdSetMode(unsigned char mode) +{ + unsigned char reg = 0x0c; + if (mode & LCD_CURSOR) + reg |= 0x2; + if (mode & LCD_CURBLINK) + reg |= 0x1; + lcdWrite(false, reg); +} + +void lcdClear() +{ + lcdWrite(false, 0x01); +} + char lcdInit() { LCD_DDDR = 0x00; diff --git a/avr_firmware/src/lcd.h b/avr_firmware/src/lcd.h index c6c927a..9c1cfda 100644 --- a/avr_firmware/src/lcd.h +++ b/avr_firmware/src/lcd.h @@ -3,9 +3,17 @@ char lcdInit(); +void lcdWriteChr(char chr); void lcdWriteStr(char const* str); void lcdWriteStrP(char const* str); +void lcdWriteStrFill(char const* str); +void lcdWriteStrFillP(char const* str); void lcdSetPos(unsigned char x, unsigned char y); +#define LCD_CURSOR 1 +#define LCD_CURBLINK 2 +void lcdSetMode(unsigned char mode); + +void lcdClear(); #endif diff --git a/avr_firmware/src/main.c b/avr_firmware/src/main.c index 5f93f2a..9dbb607 100644 --- a/avr_firmware/src/main.c +++ b/avr_firmware/src/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,14 +8,16 @@ #include #include +#include "eeprom.h" #include "timer.h" #include "modem.h" #include "uart.h" #include "lcd.h" +#include "ui.h" int main() { - const unsigned char osccal = eeprom_read_byte(0); + const unsigned char osccal = eeprom_read_byte(EEPROM_OSCCAL_OFS); OSCCAL = osccal; DDRD = 1<<7; @@ -25,37 +28,19 @@ int main() lcdInit(); uart0Init(); - lcdWriteStrP(PSTR("Hallo, Welt!")); + /* char buf[3]; */ + /* utoa(osccal, buf, 16); */ - lcdSetPos(0, 1); + /* lcdWriteStr(buf); */ - char buf[6]; - utoa(osccal, buf, 16); + screenHandler(0, KEY_NONE); - lcdWriteStrP(PSTR("OSCCAL = 0x")); - lcdWriteStr(buf); - - unsigned oldSeconds = 0; while (true) { sleep_mode(); - unsigned seconds = timerGetSeconds(); - if (seconds != oldSeconds) { - utoa(seconds, buf, 10); - lcdSetPos(0,2); - lcdWriteStr(buf); - oldSeconds = seconds; - } - char key, action = getKey(&key); if (action != KEY_NONE) { - lcdSetPos(0, 3); - utoa(key, buf, 10); - lcdWriteStr(buf); - if (action == KEY_PRESSED) - lcdWriteStrP(PSTR(" pressed! ")); - else if (action == KEY_RELEASED) - lcdWriteStrP(PSTR(" released!")); + screenHandler(key, action); } } diff --git a/avr_firmware/src/ui.c b/avr_firmware/src/ui.c new file mode 100644 index 0000000..339b231 --- /dev/null +++ b/avr_firmware/src/ui.c @@ -0,0 +1,399 @@ +#include +#include +#include +#include +#include + +#include "eeprom.h" +#include "lcd.h" +#include "timer.h" + +void writeStatusScreen() +{ + lcdClear(); + lcdWriteStrP(PSTR("DMXGSM")); + lcdSetPos(0, 1); + lcdWriteStrP(PSTR("No connection")); +} + +void writeInfoScreen(char page) +{ + char buf[8]; + + lcdClear(); + switch (page) { + case 0: + lcdWriteStrP(PSTR("Software version:")); + lcdSetPos(1, 1); + lcdWriteStrP(PSTR(VERSION)); + lcdSetPos(0, 2); + lcdWriteStrP(PSTR("Serial number:")); + lcdSetPos(1, 3); + eeprom_read_block(buf, EEPROM_SERIAL_OFS, 8); + for(char i = 0;i < 8;++i) + lcdWriteChr(buf[i]+'0'); + break; + case 1: + lcdWriteStrP(PSTR("OSCCAL:")); + lcdSetPos(1, 1); + utoa(OSCCAL, buf, 16); + lcdWriteStrP(PSTR("0x")); + lcdWriteChr(toupper(buf[0])); + lcdWriteChr(toupper(buf[1])); + break; + } +} + +void genSIMPINMenuStr(char *buf) +{ + strcpy_P(buf, PSTR("PIN: ")); + if (eeprom_read_byte(EEPROM_PIN_VALID_OFS) == 1) + strcpy_P(buf+5, PSTR("****")); + else { + buf[5] = '?'; + buf[6] = '\0'; + } +} + +void genAPNNameMenuStr(char *buf) +{ + strcpy_P(buf, PSTR("APN: ")); + if (eeprom_read_byte(EEPROM_APN_VALID_OFS) == 1) { + eeprom_read_block(buf+5, EEPROM_APN_OFS, 13); + buf[18] = '\0'; + } +} + +void genAPNUserMenuStr(char *buf) +{ + strcpy_P(buf, PSTR("User: ")); + if (eeprom_read_byte(EEPROM_APN_USER_VALID_OFS) == 1) { + eeprom_read_block(buf+6, EEPROM_APN_USER_OFS, 12); + buf[18] = '\0'; + } +} + +void genAPNPWMenuStr(char *buf) +{ + strcpy_P(buf, PSTR("Passwd: ")); + if (eeprom_read_byte(EEPROM_APN_PW_VALID_OFS) == 1) + strcpy_P(buf+8, PSTR("********")); + else { + buf[8] = '?'; + buf[9] = '\0'; + } +} + + + +enum states { + S_NONE, + S_STATUS, + S_MENU, + S_INFO, + S_EDITSIMPIN, + S_EDITAPNNAME, + S_EDITAPNUSER, + S_EDITAPNPW +}; + +typedef void (*DynamicMenuEntryFn)(char *); + +struct MenuEntry { + enum states tgtState; + const struct MenuEntry *tgtMenu; + DynamicMenuEntryFn dynFn; + PGM_P title; +}; + +typedef struct MenuEntry Menu[]; + +const char strMainMenu_Info[] PROGMEM = "Info"; +const char strMainMenu_Settings[] PROGMEM = "Settings"; +const char strSettingsMenu_SIM[] PROGMEM = "SIM Settings"; +const char strSettingsMenu_APN[] PROGMEM = "APN Settings"; + +static const Menu PROGMEM APNMenu = { + {S_EDITAPNNAME, NULL, &genAPNNameMenuStr, NULL}, + {S_EDITAPNUSER, NULL, &genAPNUserMenuStr, NULL}, + {S_EDITAPNPW, NULL, &genAPNPWMenuStr, NULL}, + {S_NONE, NULL, NULL, NULL} +}; + +static const Menu PROGMEM SIMMenu = { + {S_EDITSIMPIN, NULL, &genSIMPINMenuStr, NULL}, + {S_NONE, NULL, NULL, NULL} +}; + +static const Menu PROGMEM SettingsMenu = { + {S_NONE, SIMMenu, NULL, strSettingsMenu_SIM}, + {S_NONE, APNMenu, NULL, strSettingsMenu_APN}, + {S_NONE, NULL, NULL, NULL} +}; + +static const Menu PROGMEM MainMenu = { + {S_INFO, NULL, NULL, strMainMenu_Info}, + {S_NONE, SettingsMenu, NULL, strMainMenu_Settings}, + {S_NONE, NULL, NULL, NULL} +}; + +static unsigned char menuPos = 0, menuSPtr = 0; +static const struct MenuEntry* curMenu = MainMenu; +static const struct MenuEntry* stackMenu[4]; + +void writeMenu(unsigned char pos) +{ + char buf[19]; + + lcdClear(); + for(char line = 0;line < 4;++line) { + if (pos == line) { + lcdSetPos(0, line); + lcdWriteChr(0x7e); + } + + const char *str = pgm_read_ptr(&curMenu[line].title); + DynamicMenuEntryFn dynFn = pgm_read_ptr(&curMenu[line].dynFn); + + lcdSetPos(2, line); + if (str) + lcdWriteStrP(str); + else if (dynFn) { + dynFn(buf); + lcdWriteStr(buf); + } else + break; + } +} + +enum states menuHandler(char key, char action) +{ + unsigned char newMenuPos = menuPos; + if (action == KEY_PRESSED) { + if (key == 1) { + newMenuPos = (menuPos==0)?0:(menuPos-1); + } else if (key == 3) { + if (((pgm_read_ptr(&curMenu[menuPos+1].title)) != NULL) || + ((pgm_read_ptr(&curMenu[menuPos+1].dynFn)) != NULL)) + newMenuPos = menuPos+1; + } else if (key == 5) { + const struct MenuEntry* newMenu = pgm_read_ptr(&curMenu[menuPos].tgtMenu); + if (newMenu) { + stackMenu[menuSPtr++] = curMenu; + curMenu = newMenu; + newMenuPos = 0; + writeMenu(0); + } else + return pgm_read_byte(&curMenu[menuPos].tgtState); + } else if (key == 6) { + if (menuSPtr > 0) { + curMenu = stackMenu[--menuSPtr]; + newMenuPos = 0; + writeMenu(0); + } else + return S_STATUS; + } + } + if (newMenuPos != menuPos) { + lcdSetPos(0, menuPos); + lcdWriteChr(' '); + lcdSetPos(0, newMenuPos); + lcdWriteChr(0x7e); + menuPos = newMenuPos; + } + return S_NONE; +} + +static char numberEntryBuf[4]; +static unsigned char numberEntryPos, numberEntryX, numberEntryY; +char numberEntryHandler(char key, char action) +{ + if (action == KEY_PRESSED) { + if (key == 1) { + numberEntryBuf[numberEntryPos] = (numberEntryBuf[numberEntryPos]==0)?9:(numberEntryBuf[numberEntryPos]-1); + lcdSetPos(numberEntryX+numberEntryPos, numberEntryY); + lcdWriteChr(numberEntryBuf[numberEntryPos]+'0'); + lcdSetPos(numberEntryX+numberEntryPos, numberEntryY); + } else if (key == 3) { + numberEntryBuf[numberEntryPos] = (numberEntryBuf[numberEntryPos]==9)?0:(numberEntryBuf[numberEntryPos]+1); + lcdSetPos(numberEntryX+numberEntryPos, numberEntryY); + lcdWriteChr(numberEntryBuf[numberEntryPos]+'0'); + lcdSetPos(numberEntryX+numberEntryPos, numberEntryY); + } else if (key == 0) { + numberEntryPos = (numberEntryPos==0)?0:(numberEntryPos-1); + lcdSetPos(numberEntryX+numberEntryPos, numberEntryY); + } else if (key == 4) { + numberEntryPos = (numberEntryPos==3)?3:(numberEntryPos+1); + lcdSetPos(numberEntryX+numberEntryPos, numberEntryY); + } else if (key == 5) + return 1; + else if (key == 6) + return -1; + } + return 0; +} + +static char textEntryBuf[32]; +static unsigned char textEntryPos, textEntryX, textEntryY; +char textEntryHandler(char key, char action) +{ + if (action == KEY_PRESSED) { + if (key == 1) { + if (textEntryBuf[textEntryPos] == ' ') + textEntryBuf[textEntryPos] = 'z'; + else if (textEntryBuf[textEntryPos] == 'a') + textEntryBuf[textEntryPos] = 'Z'; + else + --textEntryBuf[textEntryPos]; + lcdSetPos(textEntryX+textEntryPos, textEntryY); + lcdWriteChr(textEntryBuf[textEntryPos]); + lcdSetPos(textEntryX+textEntryPos, textEntryY); + } else if (key == 3) { + if (textEntryBuf[textEntryPos] == 'Z') + textEntryBuf[textEntryPos] = 'a'; + else if (textEntryBuf[textEntryPos] == 'z') + textEntryBuf[textEntryPos] = ' '; + else + ++textEntryBuf[textEntryPos]; + lcdSetPos(textEntryX+textEntryPos, textEntryY); + lcdWriteChr(textEntryBuf[textEntryPos]); + lcdSetPos(textEntryX+textEntryPos, textEntryY); + } else if (key == 0) { + textEntryPos = (textEntryPos==0)?0:(textEntryPos-1); + lcdSetPos(textEntryX+textEntryPos, textEntryY); + } else if (key == 4) { + textEntryPos = (textEntryPos==10)?10:(textEntryPos+1); + lcdSetPos(textEntryX+textEntryPos, textEntryY); + } else if (key == 5) + return 1; + else if (key == 6) + return -1; + } + return 0; +} + +static unsigned char curPage; +void enterState(enum states state) +{ + switch (state) { + case S_STATUS: + lcdSetMode(0); + writeStatusScreen(); + break; + case S_MENU: + lcdSetMode(0); + writeMenu(menuPos); + break; + case S_INFO: + lcdSetMode(0); + curPage = 0; + writeInfoScreen(0); + break; + case S_EDITSIMPIN: + numberEntryPos = 0; + for (char i = 0;i < 4;++i) + numberEntryBuf[i] = 0; + numberEntryX = 7; + numberEntryY = 0; + lcdSetMode(LCD_CURBLINK); + lcdSetPos(numberEntryX, numberEntryY); + lcdWriteStrP(PSTR("0000")); + lcdSetPos(numberEntryX, numberEntryY); + break; + case S_EDITAPNNAME: + textEntryPos = 0; + memset(textEntryBuf, ' ', 32); + textEntryX = 7; + textEntryY = 0; + lcdSetMode(LCD_CURBLINK); + lcdSetPos(textEntryX, textEntryY); + break; + case S_EDITAPNUSER: + textEntryPos = 0; + memset(textEntryBuf, ' ', 32); + textEntryX = 8; + textEntryY = 1; + lcdSetMode(LCD_CURBLINK); + lcdSetPos(textEntryX, textEntryY); + break; + case S_EDITAPNPW: + textEntryPos = 0; + memset(textEntryBuf, ' ', 32); + textEntryX = 10; + textEntryY = 2; + lcdSetMode(LCD_CURBLINK); + lcdSetPos(textEntryX, textEntryY); + lcdWriteStrP(PSTR(" ")); + lcdSetPos(textEntryX, textEntryY); + break; + default: + lcdSetMode(0); + lcdClear(); + lcdWriteStrP(PSTR("NYI")); + break; + } +} + +void screenHandler(char key, char action) +{ + static enum states state = S_NONE; + enum states newState = state; + char ret; + + switch (state) { + case S_NONE: + newState = S_STATUS; + break; + case S_STATUS: + if (action == KEY_PRESSED) { + newState = S_MENU; + } + break; + case S_MENU: + newState = menuHandler(key, action); + if (newState == S_NONE) + newState = state; + break; + + case S_INFO: + if (action == KEY_PRESSED) { + if (key == 6) { + newState = S_MENU; + } else if ((key == 3) && (curPage < 1)) { + writeInfoScreen(++curPage); + } else if ((key == 1) && (curPage > 0)) { + writeInfoScreen(--curPage); + } + + } + break; + case S_EDITSIMPIN: + ret = numberEntryHandler(key, action); + if (ret == -1) + newState = S_MENU; + else if (ret == 1) { + eeprom_update_block(numberEntryBuf, EEPROM_PIN_OFS, 4); + eeprom_update_byte(EEPROM_PIN_VALID_OFS, 1); + newState = S_MENU; + } + break; + case S_EDITAPNNAME: + case S_EDITAPNUSER: + case S_EDITAPNPW: + ret = textEntryHandler(key, action); + if (ret == -1) + newState = S_MENU; + break; + default: + if (action == KEY_PRESSED) { + if (key == 6) { + newState = S_MENU; + } + } + } + + if (newState != state) { + enterState(newState); + state = newState; + } +} diff --git a/avr_firmware/src/ui.h b/avr_firmware/src/ui.h new file mode 100644 index 0000000..f82dee8 --- /dev/null +++ b/avr_firmware/src/ui.h @@ -0,0 +1,6 @@ +#ifndef DMXGSM_AVR_UI_H +#define DMXGSM_AVR_UI_H + +void screenHandler(char key, char action); + +#endif