aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--accel.c4
-rw-r--r--accel.h1
-rw-r--r--gyro.c18
-rw-r--r--gyro.h3
-rw-r--r--main.c42
-rw-r--r--ui.c232
-rw-r--r--ui.h7
8 files changed, 261 insertions, 48 deletions
diff --git a/Makefile b/Makefile
index 335cc51..f3d4b0d 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/accel.c b/accel.c
index 3a6c595..1bca794 100644
--- a/accel.c
+++ b/accel.c
@@ -188,6 +188,10 @@ uint8_t accelGetShakeCount () {
return shakeCount;
}
+void accelResetShakeCount () {
+ shakeCount = 0;
+}
+
horizon accelGetHorizon () {
return horizonSign;
}
diff --git a/accel.h b/accel.h
index 4e53160..092bd1e 100644
--- a/accel.h
+++ b/accel.h
@@ -11,6 +11,7 @@ void accelStart ();
bool accelProcess ();
int8_t accelGetZ ();
uint8_t accelGetShakeCount ();
+void accelResetShakeCount ();
horizon accelGetHorizon ();
#endif /* ACCEL_H */
diff --git a/gyro.c b/gyro.c
index b9cba41..6a32ef3 100644
--- a/gyro.c
+++ b/gyro.c
@@ -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;
+}
+
diff --git a/gyro.h b/gyro.h
index 9297a6f..0620093 100644
--- a/gyro.h
+++ b/gyro.h
@@ -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 */
diff --git a/main.c b/main.c
index 015abc3..37592a7 100644
--- a/main.c
+++ b/main.c
@@ -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 ();
diff --git a/ui.c b/ui.c
new file mode 100644
index 0000000..0c2bb2c
--- /dev/null
+++ b/ui.c
@@ -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
+ }
+}
+
diff --git a/ui.h b/ui.h
new file mode 100644
index 0000000..e46a817
--- /dev/null
+++ b/ui.h
@@ -0,0 +1,7 @@
+#ifndef UI_H
+#define UI_H
+
+void uiLoop ();
+
+#endif /* UI_H */
+