diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | accel.c | 4 | ||||
-rw-r--r-- | accel.h | 1 | ||||
-rw-r--r-- | gyro.c | 18 | ||||
-rw-r--r-- | gyro.h | 3 | ||||
-rw-r--r-- | main.c | 42 | ||||
-rw-r--r-- | ui.c | 232 | ||||
-rw-r--r-- | ui.h | 7 |
8 files changed, 261 insertions, 48 deletions
@@ -3,7 +3,7 @@ CFLAGS=-Os -Wall -Wextra all: sanduhr.hex -sanduhr.elf: main.c i2c.c i2c.h uart.c uart.h timer.c timer.h gyro.c gyro.h accel.c accel.h common.h speaker.c speaker.h pwm.c pwm.h +sanduhr.elf: main.c i2c.c i2c.h uart.c uart.h timer.c timer.h gyro.c gyro.h accel.c accel.h common.h speaker.c speaker.h pwm.c pwm.h ui.c ui.h avr-gcc -std=gnu99 -mmcu=$(MCU) $(CFLAGS) -o $@ $^ sanduhr.hex: sanduhr.elf @@ -188,6 +188,10 @@ uint8_t accelGetShakeCount () { return shakeCount; } +void accelResetShakeCount () { + shakeCount = 0; +} + horizon accelGetHorizon () { return horizonSign; } @@ -11,6 +11,7 @@ void accelStart (); bool accelProcess (); int8_t accelGetZ (); uint8_t accelGetShakeCount (); +void accelResetShakeCount (); horizon accelGetHorizon (); #endif /* ACCEL_H */ @@ -24,7 +24,7 @@ static volatile int16_t zval = 0; /* accumulated z value */ static int32_t zaccum = 0; /* calculated zticks */ -static int8_t zticks = 0; +static int16_t zticks = 0; /* currently reading from i2c */ static bool reading = false; @@ -66,16 +66,18 @@ void gyroStart () { */ static void gyroProcessTicks () { const uint8_t shift = 14; + const uint32_t max = (1 << shift); + const uint32_t mask = ~(max-1); - if (zaccum > (1 << shift)) { + if (zaccum > (int32_t) max) { const uint32_t a = abs (zaccum); zticks += a >> shift; /* mask shift bits */ - zaccum -= a & (~0x3ff); - } else if (zaccum < -(1 << shift)) { + zaccum -= a & mask; + } else if (zaccum < -((int32_t) max)) { const uint32_t a = abs (zaccum); zticks -= a >> shift; - zaccum += a & (~0x3ff); + zaccum += a & mask; } } @@ -123,7 +125,11 @@ int16_t gyroGetZRaw () { return zval; } -int8_t gyroGetZTicks () { +int16_t gyroGetZTicks () { return zticks; } +void gyroResetZTicks () { + zticks = 0; +} + @@ -10,7 +10,8 @@ bool gyroProcess (); void gyroResetAccum (); int32_t gyroGetZAccum (); int16_t gyroGetZRaw (); -int8_t gyroGetZTicks (); +int16_t gyroGetZTicks (); +void gyroResetZTicks (); #endif /* GYROSCOPE_H */ @@ -3,7 +3,6 @@ #include <avr/io.h> #include <avr/interrupt.h> #include <avr/sleep.h> -#include <util/delay.h> #include <stdio.h> #include <stdbool.h> #include <stdlib.h> @@ -15,6 +14,7 @@ #include "accel.h" #include "speaker.h" #include "pwm.h" +#include "ui.h" static void cpuInit () { /* enter change prescaler mode */ @@ -49,46 +49,8 @@ int main () { accelStart (); pwmStart (); -#if 0 - speakerStart (); - _delay_ms (200); - speakerStop (); -#endif - - timerStart (); - bool checkGyro = false; - while (1) { - while (!timerHit ()) { - for (uint8_t i = 0; i < 6; i++) { - pwmSetBrightness (i, abs (gyroGetZTicks ())); - } + uiLoop (); - /* round-robin to prevent starvation */ - if (checkGyro) { - gyroProcess (); - accelProcess(); - } else { - accelProcess (); - gyroProcess (); - } - checkGyro = !checkGyro; - sleep_enable (); - sleep_cpu (); - sleep_disable (); - } - - printf ("t=%i, h=%i, s=%i\n", gyroGetZTicks (), accelGetHorizon (), - accelGetShakeCount ()); -#if 0 - volatile const int32_t *gyroval = gyroGetAccum (); - volatile const int16_t *gyroraw = gyroGetRaw (); - volatile const int8_t *accelval = accelGet (); - printf ("%li/%li/%li - %i/%i/%i - %i/%i/%i\n", - gyroval[0], gyroval[1], gyroval[2], - gyroraw[0], gyroraw[1], gyroraw[2], - accelval[1], accelval[3], accelval[5]); -#endif - } timerStop (); pwmStop (); @@ -0,0 +1,232 @@ +#include "common.h" + +#include <util/delay.h> +#include <avr/sleep.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include "ui.h" +#include "accel.h" +#include "gyro.h" +#include "speaker.h" +#include "timer.h" +#include "pwm.h" + +typedef enum { + /* initialize */ + UIMODE_INIT, + /* deep sleep */ + UIMODE_SLEEP, + /* select time */ + UIMODE_SELECT, + /* idle, showing time */ + UIMODE_IDLE, + /* count time */ + UIMODE_RUN, + /* alert */ + UIMODE_ALARM, +} uimode; + +static uimode mode = UIMODE_INIT; +/* timer seconds */ +static int16_t seconds = 0; +static horizon h = HORIZON_NONE; +static bool horizonChanged = false; + +static void processSensors () { + static bool checkGyro = false; + + /* round-robin to prevent starvation */ + if (checkGyro) { + gyroProcess (); + accelProcess(); + } else { + accelProcess (); + gyroProcess (); + } + checkGyro = !checkGyro; +} + +/* + * We use the following LED coding (top to bottom): + * 1-5 minutes: (off) (5m ) (4m ) (3m ) (2m ) (1m ) + * 5-60 minutes: (on ) (50m) (40m) (30m) (20m) (10m) + */ +static void updateLeds () { + /* XXX: orientation */ + if (seconds <= 5*60) { + const uint8_t minutes = seconds / 60; + for (uint8_t i = 0; i < minutes; i++) { + pwmSetBlink (i, PWM_BLINK_ON); + } + /* 10 second steps */ + pwmSetBlink (minutes, (seconds - minutes*60)/10); + for (uint8_t i = minutes+1; i < 6; i++) { + pwmSetBlink (i, PWM_BLINK_OFF); + } + } else { + const uint8_t tenminutes = seconds/60/10; + for (uint8_t i = 0; i < tenminutes; i++) { + pwmSetBlink (i, PWM_BLINK_ON); + } + /* 2 minute steps */ + pwmSetBlink (tenminutes, (seconds - tenminutes*10*60)/60/2); + for (uint8_t i = tenminutes+1; i < 5; i++) { + pwmSetBlink (i, PWM_BLINK_OFF); + } + pwmSetBlink (5, PWM_BLINK_ON); + } +} + +#define sign(x) ((x < 0) ? -1 : 1) + +/* Timer value selection + * + */ +static void doSelect () { + if (accelGetShakeCount () >= 2) { + /* stop selection */ + accelResetShakeCount (); + mode = UIMODE_IDLE; + printf ("select->idle(%i)\n", seconds); + speakerStart (); + _delay_ms (50); + speakerStop (); + return; + } + + /* use zticks as seconds */ + const int16_t zticks = gyroGetZTicks (); + if (abs (zticks) > 0) { + gyroResetZTicks (); + if (seconds > 5*60) { + /* 1 minute steps */ + const int16_t newseconds = seconds + sign (zticks) * 60; + /* when decrementing one minute steps might be too much */ + if (newseconds < 5*60) { + seconds = 5*60; + } else { + seconds = newseconds; + } + } else { + /* 10 second steps */ + seconds += sign (zticks) * 10; + } + if (seconds < 0) { + seconds = 0; + } else if (seconds > 60*60) { + seconds = 60*60; + } + printf ("%i\n", seconds); + } + + updateLeds (); +} + +static void doIdle () { + if (horizonChanged && seconds > 0) { + /* start timer */ + mode = UIMODE_RUN; + timerStart (); + printf ("idle->run\n"); + speakerStart (); + _delay_ms (50); + speakerStop (); + } else if (accelGetShakeCount () >= 2) { + /* set timer */ + accelResetShakeCount (); + mode = UIMODE_SELECT; + printf ("idle->select\n"); + speakerStart (); + _delay_ms (50); + speakerStop (); + return; + } +} + +static void doRun () { + if (timerHit ()) { + --seconds; + printf ("run: %i\n", seconds); + updateLeds (); + if (seconds == 0) { + speakerStart (); + _delay_ms (50); + speakerStop (); + mode = UIMODE_IDLE; + printf ("run->idle\n"); + } + } else if (horizonChanged) { + /* stop timer */ + mode = UIMODE_IDLE; + printf ("run->idle (stopped)\n"); + } +} + +static void doInit () { + /* get initial orientation */ + h = accelGetHorizon (); + if (h != HORIZON_NONE) { + mode = UIMODE_IDLE; + printf ("init->idle\n"); + updateLeds (); + } +} + +static void cpuSleep () { + sleep_enable (); + sleep_cpu (); + sleep_disable (); +} + +/* Main loop + */ +void uiLoop () { + while (1) { + processSensors (); + + horizon newh = accelGetHorizon (); + if (newh != h) { + horizonChanged = true; + } else { + horizonChanged = false; + } + + switch (mode) { + case UIMODE_INIT: + doInit (); + break; + + case UIMODE_SELECT: + doSelect (); + break; + + case UIMODE_IDLE: + doIdle (); + break; + + case UIMODE_RUN: + doRun (); + break; + + default: + assert (0 && "invalid ui mode"); + break; + } + cpuSleep (); + +#if 0 + printf ("t=%i, h=%i, s=%i\n", gyroGetZTicks (), accelGetHorizon (), + accelGetShakeCount ()); + volatile const int32_t *gyroval = gyroGetAccum (); + volatile const int16_t *gyroraw = gyroGetRaw (); + volatile const int8_t *accelval = accelGet (); + printf ("%li/%li/%li - %i/%i/%i - %i/%i/%i\n", + gyroval[0], gyroval[1], gyroval[2], + gyroraw[0], gyroraw[1], gyroraw[2], + accelval[1], accelval[3], accelval[5]); +#endif + } +} + @@ -0,0 +1,7 @@ +#ifndef UI_H +#define UI_H + +void uiLoop (); + +#endif /* UI_H */ + |