avr_firmware: WIP: UI and settings

This commit is contained in:
2015-06-25 22:22:23 +02:00
parent c7d0ff3873
commit 80f87d2513
7 changed files with 487 additions and 26 deletions

View File

@@ -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

16
avr_firmware/src/eeprom.h Normal file
View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -1,5 +1,6 @@
#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/io.h>
@@ -7,14 +8,16 @@
#include <avr/pgmspace.h>
#include <util/delay.h>
#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);
}
}

399
avr_firmware/src/ui.c Normal file
View File

@@ -0,0 +1,399 @@
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#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;
}
}

6
avr_firmware/src/ui.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef DMXGSM_AVR_UI_H
#define DMXGSM_AVR_UI_H
void screenHandler(char key, char action);
#endif