TDT4160/o3/o3.c

253 lines
4.9 KiB
C

#include "o3.h"
#include "gpio.h"
#include "systick.h"
/**************************************************************************/ /**
* @brief Konverterer nummer til string
* Konverterer et nummer mellom 0 og 99 til string
*****************************************************************************/
void int_to_string(char *timestamp, unsigned int offset, int i)
{
if (i > 99)
{
timestamp[offset] = '9';
timestamp[offset + 1] = '9';
return;
}
while (i > 0)
{
if (i >= 10)
{
i -= 10;
timestamp[offset]++;
}
else
{
timestamp[offset + 1] = '0' + i;
i = 0;
}
}
}
/**************************************************************************/ /**
* @brief Konverterer 3 tall til en timestamp-string
* timestamp-argumentet må være et array med plass til (minst) 7 elementer.
* Det kan deklareres i funksjonen som kaller som "char timestamp[7];"
* Kallet blir dermed:
* char timestamp[7];
* time_to_string(timestamp, h, m, s);
*****************************************************************************/
void time_to_string(char *timestamp, int h, int m, int s)
{
timestamp[0] = '0';
timestamp[1] = '0';
timestamp[2] = '0';
timestamp[3] = '0';
timestamp[4] = '0';
timestamp[5] = '0';
timestamp[6] = '\0';
int_to_string(timestamp, 0, h);
int_to_string(timestamp, 2, m);
int_to_string(timestamp, 4, s);
}
/* -------------------------------------------------------------------------- */
typedef struct {
word CTRL;
word MODEL;
word MODEH;
word DOUT;
word DOUTSET;
word DOUTCLR;
word DOUTTGL;
word DIN;
word PINLOCKN;
} gpio_port_map_t;
typedef volatile struct {
gpio_port_map_t ports[6];
word unused_space[10];
word EXTIPSELL;
word EXTIPSELH;
word EXTIRISE;
word EXTIFALL;
word IEN;
word IF;
word IFS;
word IFC;
word ROUTE;
word INSENSE;
word LOCK;
word CTRL;
word CMD;
word EM4WUEN;
word EM4WUPOL;
word EM4WUCAUSE;
} gpio_t;
typedef volatile struct {
word CTRL;
word LOAD;
word VAL;
word CALIB;
} systick_t;
static volatile gpio_t* const gpio = (gpio_t*) GPIO_BASE;
static volatile systick_t* const systick = (systick_t*) SYSTICK_BASE;
#define GPIO_LED GPIO_PORT_E
#define GPIO_PB GPIO_PORT_B
#define LED_PIN 2
#define PB0_PIN 9
#define PB1_PIN 10
/* -------------------------------------------------------------------------- */
enum PROGRAM_STATE {
ADD_SECS,
ADD_MINS,
ADD_HOURS,
COUNTDOWN,
ALARM,
PROGRAM_STATE_SIZE,
};
static struct {
char display[7];
unsigned char hours;
unsigned char minutes;
unsigned char seconds;
unsigned char programState;
} state;
void initializeState() {
state.hours = 0;
state.minutes = 0;
state.seconds = 0;
state.programState = ADD_SECS;
}
void initializeInterruptHandlers()
{
// Setup SYSTICK
systick->CTRL = 0b111;
systick->LOAD = FREQUENCY;
systick->VAL = 1;
// Setup LED
volatile word* setting;
setting = &gpio->ports[GPIO_LED].MODEL;
*setting &= ~(0xF << (4 * LED_PIN));
*setting += GPIO_MODE_OUTPUT << (4 * LED_PIN);
// Setup buttons
for (char i=0; i<2; i++) {
setting = i ? &gpio->ports[GPIO_PB].MODEH : &gpio->EXTIPSELH;
*setting &= ~(0xFF << 4);
*setting += 0x110;
word button = i ? PB0_PIN : PB1_PIN;
gpio->EXTIFALL |= (1 << button);
gpio->IEN |= (1 << button);
}
}
void activateAlarm()
{
state.programState = ALARM;
gpio->ports[GPIO_LED].DOUTSET = 1 << LED_PIN;
}
void deactivateAlarm()
{
gpio->ports[GPIO_LED].DOUTCLR = 1 << LED_PIN;
}
void turnToNextState()
{
if (state.programState == COUNTDOWN) return;
if (state.programState == ALARM)
deactivateAlarm();
state.programState++;
state.programState %= PROGRAM_STATE_SIZE;
}
void updateScreen()
{
time_to_string(state.display, state.hours, state.minutes, state.seconds);
lcd_write(state.display);
}
/* -------------------------------------------------------------------------- */
void SysTick_Handler()
{
gpio->ports[GPIO_LED].DOUTTGL = 1;
if (state.programState != COUNTDOWN) return;
if (!state.seconds) {
if (!state.minutes) {
if (!state.hours) {
activateAlarm();
return;
}
state.hours--;
state.minutes = 60;
return;
}
state.minutes--;
state.seconds = 60;
return;
}
state.seconds--;
}
// PB0
void GPIO_ODD_IRQHandler()
{
switch (state.programState)
{
case ADD_SECS:
state.seconds++;
state.seconds %= 60;
break;
case ADD_MINS:
state.minutes++;
state.minutes %= 60;
break;
case ADD_HOURS:
state.hours++;
break;
}
gpio->IFC = 1 << PB0_PIN;
}
// PB1
void GPIO_EVEN_IRQHandler()
{
turnToNextState();
gpio->IFC = 1 << PB1_PIN;
}
/* -------------------------------------------------------------------------- */
int main(void)
{
init();
initializeInterruptHandlers();
initializeState();
for (;;) {
updateScreen();
__asm__("WFI");
}
return 0;
}