src/timer.c
changeset 78 504c2310cddb
parent 63 e9b478c817df
--- a/src/timer.c	Sun Apr 20 21:55:44 2014 +0300
+++ b/src/timer.c	Sun Apr 20 22:47:41 2014 +0300
@@ -18,11 +18,16 @@
     );
     TCCR1B = (
             // CTC mode
-            0b01 << WGM12 
+            0b01 << WGM12
     );
     TCCR1C = 0;
 }
 
+static void timer1_set ()
+{
+    sbi(&TIMER_FLAGS, TIMER1_BUSY);
+}
+
 void timer1_start (short cycles)
 {
     // count up from zero...
@@ -32,7 +37,7 @@
     OCR1A = cycles;
 
     // start!
-    sbi(&TIMER_FLAGS, TIMER1_BUSY);
+    timer1_set();
     TIMSK1 = (
             // OCA interrupt
             0b1 << OCIE1A       // enable
@@ -46,58 +51,76 @@
     );
 }
 
+/*
+ * Keep the timer running, but clear the flag..
+ */
+static void timer1_clear ()
+{
+    cbi(&TIMER_FLAGS, TIMER1_BUSY);
+}
+
+/*
+ * Stop the timer at its current value.
+ */
 static void timer1_stop ()
 {
     // WGM: normal
     // clocksource: stop
     TCCR1B = 0;
 
-    cbi(&TIMER_FLAGS, TIMER1_BUSY);
+    timer1_clear();
 }
 
 ISR(TIMER1_COMPA_vect)
 {
-    timer1_stop();
+    timer1_clear();
 
-    // XXX: cpu will automatically wake up from sleep()
+    // cpu will wake up from sleep()
 }
 
 /*
  * Sleep on timer1 interrupt.
  *
- * Returns 0 on interrupt, 1 on timeout.
+ * Starts fresh timer that sleeps given cycles if given, or continues on the running timer.
+ *
+ * Returns 1 on timeout, 0 on other interrupt.
  */
 char timer_sleep (unsigned cycles)
 {
     if (cycles) {
-        // set timer
+        // set fresh timer
         timer1_start(cycles);
+    } else {
+        // wait for next cycle...
+        timer1_set();
     }
 
-    // sleep
-    // TODO: PRR
-    SMCR = (
-            // idle sleep
-            (0b00 << SM0)
+    // sleep while timer is running
+    // XXX: atomic?
+    if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
+        // TODO: PRR
+        SMCR = (
+                // idle sleep
+                (0b00 << SM0)
 
-            // enable sleep
-        |   (0b1 << SE)
-    );
-    
-    // sleep
-    __asm__ ( "sleep" :: );
+                // enable sleep
+            |   (0b1 << SE)
+        );
 
-    // cleanup
-    SMCR = 0;
-    
-    if (cycles && !tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
+        // sleep
+        __asm__ ( "sleep" :: );
+
+        // cleanup
+        SMCR = 0;
+    }
+
+    if (tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
+        // interrupt
+        return 0;
+
+    } else {
         // timeout
         return 1;
-    } else {
-        timer1_stop();
-
-        // interrupt
-        return 0;
     }
 }