dmx: split out dmx.c module; implement console
authorTero Marttila <terom@paivola.fi>
Fri, 11 Apr 2014 14:42:30 +0300
changeset 65 625f34328820
parent 64 f9221fa50c75
child 66 0cf14786b909
dmx: split out dmx.c module; implement console
src/dmx.c
src/hello-dmx.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dmx.c	Fri Apr 11 14:42:30 2014 +0300
@@ -0,0 +1,57 @@
+#include <util/delay.h>
+
+// DMX
+#define DMX_DDR     DDRB
+#define DMX_PORT    PORTB
+#define DMX_DATA    3       // SPI MOSI
+
+// baud rate: 250k = 4µs / bit
+#define DMX_BAUD    (250 * 1000)
+#define DMX_US      4
+
+// CPU cycles / bit: 64 @ 16Mhz
+#define DMX_CYCLES  (F_CPU / DMX_BAUD)
+
+void dmx_init ()
+{
+    // dmx data out: idle (high)
+    sbi(&DMX_PORT, DMX_DATA);
+    sbi(&DMX_DDR, DMX_DATA);
+}
+
+static inline void dmx_high ()
+{
+    sbi(&DMX_PORT, DMX_DATA);
+}
+
+static inline void dmx_low ()
+{
+    cbi(&DMX_PORT, DMX_DATA);
+}
+
+#define dmx_pause(bits) _delay_us((DMX_US * bits))
+
+static void dmx_break ()
+{
+    // break
+    dmx_low();
+    dmx_pause(22);
+
+    // mark-after-break (MAB)
+    dmx_high();
+    dmx_pause(2);
+}
+
+#include "dmx_frame.c"
+
+static void dmx_packet (byte r, byte g, byte b)
+{
+    dmx_break();
+    dmx_frame(0);
+
+    dmx_frame(0);       // control
+    dmx_frame(r);
+    dmx_frame(g);
+    dmx_frame(b);
+    dmx_frame(0);       // madness
+}
--- a/src/hello-dmx.c	Fri Apr 11 14:42:19 2014 +0300
+++ b/src/hello-dmx.c	Fri Apr 11 14:42:30 2014 +0300
@@ -5,9 +5,11 @@
  */
 
 #include <avr/io.h>
-#include <util/delay.h>
 
 #include "stdlib.h"
+#include "timer.c"
+#include "serial.c"
+#include "dmx.c"
 
 // debug
 #define DEBUG_DDR   DDRB
@@ -34,72 +36,171 @@
     xbi(&DEBUG_PORT, DEBUG_LED);
 }
 
-// DMX
-#define DMX_DDR     DDRB
-#define DMX_PORT    PORTB
-#define DMX_DATA    3       // SPI MOSI
+// dmx
+/*
+ * DMX state
+ */
+static struct dmx_state {
+    byte out[256];
+    byte count;
+} dmx;
 
-// baud rate: 250k = 4µs / bit
-#define DMX_BAUD    (250 * 1000)
-#define DMX_US      4
 
-// CPU cycles / bit: 64 @ 16Mhz
-#define DMX_CYCLES  (F_CPU / DMX_BAUD)
+enum state {
+    START       = '\n',
+    CMD         = ';',
+    ARG         = ',',
+    ERROR       = '!',
+};
 
-void dmx_init ()
+enum cmd {
+    CMD_
+};
+
+#define CONSOLE_ARGS 8
+
+/*
+ * Console input state.
+ */
+static struct console {
+    enum state state;
+
+    enum cmd cmd;
+    char argc;
+    char argv[CONSOLE_ARGS];
+} console;
+
+/*
+ * Process console command.
+ */
+int command ()
 {
-    // dmx data out: idle (high)
-    sbi(&DMX_PORT, DMX_DATA);
-    sbi(&DMX_DDR, DMX_DATA);
+    switch (console.cmd) {
+        default:
+            return '?';
+    }
 }
 
-static inline void dmx_high ()
+/*
+ * Process console input.
+ */
+char input (char c)
 {
-    sbi(&DMX_PORT, DMX_DATA);
-}
+    // control
+    if (c == '\r') {
+        char ret = '?';
 
-static inline void dmx_low ()
-{
-    cbi(&DMX_PORT, DMX_DATA);
+        if (console.state == CMD) {
+            console.argc = 0;
+        } else if (console.state == ARG) {
+            console.argc++;
+        } else {
+            console.state = START;
+            return '\n';
+        }
+
+        // command
+        if ((ret = command(console.cmd))) {
+
+        } else {
+            ret = '\n';
+        }
+        
+        // return to START with response
+        console.state = START;
+        return ret;
+    
+    } else if (c == ' ' || c == '\t') {
+        // argument
+        if (console.state == CMD) {
+            console.state = ARG;
+            console.argc = 0;
+
+            return c;
+
+        } else if (console.state == ARG) {
+            if (console.argc++ < CONSOLE_ARGS) {
+                console.argv[console.argc] = 0;
+
+                return c;
+            }
+        }
+
+    // printable    
+    } else if (32 < c && c < 128) {
+        // process input char
+        if (console.state == START)  {
+            console.cmd = c;
+            console.state = CMD;
+
+            return c;
+
+        } else if (console.state == ARG) {
+            if (c >= '0' && c <= '9') {
+                console.argv[console.argc] *= 10;
+                console.argv[console.argc] += (c - '0');
+
+                return c;
+            }
+        }
+    } else {
+        // ignore
+        return ' ';
+    }
+        
+    // reject
+    console.state = ERROR;
+    return ERROR;
 }
 
-#define dmx_pause(bits) _delay_us((DMX_US * bits))
-
-static void dmx_break ()
-{
-    // break
-    dmx_low();
-    dmx_pause(22);
-
-    // mark-after-break (MAB)
-    dmx_high();
-    dmx_pause(2);
-}
-
-#include "dmx_frame.c"
-
-static void dmx_packet (byte r, byte g, byte b)
+/*
+ * Tick output state
+ */
+void update ()
 {
     dmx_break();
     dmx_frame(0);
 
-    dmx_frame(0);       // control
-    dmx_frame(r);
-    dmx_frame(g);
-    dmx_frame(b);
-    dmx_frame(0);       // madness
+    for (byte i = 0; i < dmx.count; i++) {
+        dmx_frame(dmx.out[i]);
+    }
 }
 
 void main ()
 {
     led_init();
-    dmx_init();
+    timer_init();
+    serial_init();
+    //dmx_init();
 
-    // dmx
+    // mainloop
+    char c = '>';
+    unsigned timeout = 8000; // 2Hz
+    
+    sei();
+
     while (true) {
-        dmx_packet(0x00, 0x00, 0xff);
-        dmx_pause(100);
+        // sleep
+        //led_on();
+        if (timer_sleep(timeout)) {
+            c = '.';
 
+        } else if ((c = serial_read())) {
+            // got serial data
+            c = input(c);
+
+        } else {
+            // unknown interrupt
+            c = '?';
+        }
+        //led_off();
+        
+        // respond
+        serial_write(c);
+        
+        // output
+        update();
+        
         led_toggle();
     }
 }