]> mj.ucw.cz Git - misc.git/commitdiff
The Sphinx v0.9
authorMartin Mares <mj@ucw.cz>
Sun, 12 Mar 2017 11:36:46 +0000 (12:36 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 12 Mar 2017 11:36:46 +0000 (12:36 +0100)
sphinx/sphinx.c

index 7355d0b4fda14b4f155980e13bd5e9ddb45c94a8..5f3e3f2ddb99e462cc58660df6f3d5be59a2137b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     Asking Riddles at the Entrance to Garage
+ *     The Sphinx -- A Device for Asking Riddles at the Entrance to the Garage
  *
  *     (c) 2017 Martin Mares <mj@ucw.cz>
  */
@@ -9,19 +9,24 @@
  *
  *                     +-------------------+
  *                     | RESET*        VCC |
- *     button          | PB3           SCK |
+ *     button*         | PB3           SCK |
  *     output          | PB4          MISO |
  *                     | GND      PB0=MOSI |   diagnostic LED*
  *                     +-------------------+
+ *
+ *     Note that MOSI is used for programming, so the LED is connected
+ *     via jumper, which must be open during programming.
  */
 
 #define F_CPU 1200000UL
 
+#include <avr/interrupt.h>
 #include <avr/io.h>
 #include <avr/sleep.h>
 #include <util/delay.h>
 
 typedef uint8_t byte;
+typedef uint16_t u16;
 
 #define B(x) (1U<<(x))
 
@@ -33,32 +38,115 @@ static void sleep(uint16_t millisec)
        }
 }
 
+static byte out_pulse;
+#define OUT_PULSE_WIDTH 100
+static byte debounce;
+#define DEBOUNCE_THRESHOLD 3
+static byte pressed;
+static u16 press_timer;
+#define LONG_PRESS 500
+static byte second_timer;
+static byte unlocked;
+#define UNLOCK_SECONDS 20
+
+ISR(TIM0_COMPA_vect)
+{
+       if (out_pulse) {
+               if (!--out_pulse)
+                       PORTB &= ~B(PB4);
+       }
+
+       if (!second_timer) {
+               second_timer = 100;
+               if (unlocked)
+                       unlocked--;
+       }
+       second_timer--;
+
+       if (PINB & B(PB3)) {
+               // Switch open
+               if (debounce)
+                       debounce--;
+               else
+                       pressed = 0;
+       } else {
+               // Switch closed
+               if (debounce < DEBOUNCE_THRESHOLD)
+                       debounce++;
+               else
+                       pressed = 1;
+       }
+
+       if (unlocked) {
+               if (!(second_timer & 7))
+                       PORTB ^= B(PB0);
+               if (pressed) {
+                       if (out_pulse < 2)
+                               out_pulse = 2;
+                       PORTB |= B(PB4);
+                       unlocked = UNLOCK_SECONDS;
+               }
+       } else {
+               if (!pressed) {
+                       PORTB |= B(PB0);
+                       press_timer = 0;
+               } else {
+                       PORTB &= ~B(PB0);
+                       if (press_timer < LONG_PRESS) {
+                               press_timer++;
+                               if (press_timer == LONG_PRESS) {
+                                       out_pulse = OUT_PULSE_WIDTH;
+                                       PORTB |= B(PB4);
+                                       unlocked = UNLOCK_SECONDS;
+                               }
+                       }
+               }
+       }
+}
+
 int main(void)
 {
-       DDRB |= B(PB0);                 // PB0: output
-       DDRB |= B(PB4);                 // PB4: output
-       PORTB &= ~B(PB3);               // PB3: input, no pullup
+       // PB0: output for diagnostic LED
+       DDRB |= B(PB0);
+
+       // PB3: button input, needs pull up
+       PORTB |= B(PB3);
+
+       // PB4: output to control the gate
+       PORTB &= ~B(PB4);
+       DDRB |= B(PB4);
 
        for (byte i=0; i<5; i++) {
                PORTB &= ~B(PB0);
-               sleep(100);
+               sleep(50);
                PORTB |= B(PB0);
-               sleep(100);
+               sleep(50);
        }
 
+#if 0
+       // Copy mode
        for (;;) {
                sleep(10);
                if (PINB & B(PB3)) {
-                       PORTB &= ~B(PB0);
-                       PORTB |= B(PB4);
-               } else {
                        PORTB |= B(PB0);
                        PORTB &= ~B(PB4);
+               } else {
+                       PORTB &= ~B(PB0);
+                       PORTB |= B(PB4);
                }
        }
+#endif
+
+       // Set up timer interrupt
+       TCCR0A = 0x02;                  // No OC pins, clear on compare
+       TCCR0B = 0x05;                  // Run at CLK_IO / 1024
+       OCR0A = 11;                     // Approximately once in 10ms
+       TIMSK0 = B(OCIE0A);             // Interrupt on compare
+       sei();
 
+       // Sleep well, my little sphinx
        for (;;) {
-               set_sleep_mode(SLEEP_MODE_PWR_DOWN);
+               set_sleep_mode(SLEEP_MODE_IDLE);
                sleep_mode();
        }
 }