A better state machine.
[dmxpainter.git] / src / dmx.c
1 #include "dmx.h"
2
3 #include "mcu.h"
4
5 #include "sched.h"
6
7 #include "buffer.h"
8
9
10
11
12 void set_timer(int8_t ms)
13 {
14   // Set counter to trigger correct overflow.
15   TCNT0 = 0xFF - 2 * ms;
16
17   // Enable timer interrupt (p72)
18   bits_on(TIMSK, TOIE0);
19 }
20
21 void set_timer_off(void)
22 {
23   // Disable timer interrupt (p72).
24   bits_off(TIMSK, TOIE0);
25 }
26
27 void set_trigger_rising(void)
28 {
29   // Trigger on rising edge.
30   bits_on(MCUCR, ISC00);
31
32   // Enable interrupt.
33   bits_on(GICR, INT0);
34 }
35
36 void set_trigger_falling(void)
37 {
38   // Trigger on falling edge.
39   bits_off(MCUCR, ISC00);
40
41   // Enable interrupt.
42   bits_on(GICR, INT0);
43 }
44
45 void set_trigger_off(void)
46 {
47   // Disable interrupt.
48   bits_off(GICR, INT0);
49 }
50
51 ///////////////////////////////
52
53 void dmx_init(void)
54 {
55   // Use a frequency prescaler of 8 (p72).
56   bits_mask_on(TCCR0, 1 << CS01);
57
58   // Configure as input.
59   pin_in(PIN_DMX);
60
61   // Prepare INT0, set_trigger_* will toggle between edges.
62   set_trigger_off();
63   bits_on(MCUCR, ISC01);
64
65   // Enable interrupt after a short while.
66   set_timer(10);
67 }
68
69 ///////////////////////////////
70
71 enum state_enum {
72   STATE_IDLE,
73   STATE_WAIT,
74   STATE_MARK,
75   STATE_SYNC,
76   STATE_READ,
77   STATE_STOR
78 };
79
80 uint8_t  g_package_buffer;
81 uint8_t  g_package_mask;
82 int16_t  g_package_index;
83 enum state_enum g_state = STATE_IDLE;
84
85 void dmx_int_timer0_ovf(void)
86 {
87   // Disable this interrupt.
88   set_timer_off();
89
90   switch (g_state)
91   {
92     case STATE_IDLE: {
93       // The line must be High when idle.
94       if (pin_is_set(PIN_DMX)) {
95         // Wait for start of Reset.
96         set_trigger_falling();
97       }
98       else {
99         // Wait for High.
100         set_timer(10);
101       }
102       break;
103     }
104     
105     case STATE_WAIT: {
106       // Reset was held for 88 us, wait for end of Mark now.
107       mcu_debug();
108       set_trigger_falling();
109       g_package_index = -1;
110       g_state = STATE_MARK;
111       break;
112     }
113
114     case STATE_SYNC: {
115       // Now read the data, LSB first.
116       set_timer(4);
117       g_package_mask = bits_uint8(0, 0, 0, 0, 0, 0, 0, 1);
118       g_state = STATE_READ;
119       break;
120     }
121
122     case STATE_READ: {
123       // Prepare next timer.
124       set_timer(4);
125
126       // Read bit.
127       if (pin_is_set(PIN_DMX)) {
128         bits_mask_on( g_package_buffer, g_package_mask);
129       } else {
130         bits_mask_off(g_package_buffer, g_package_mask);
131       }
132
133       // Prepare next bit.
134       g_package_mask <<= 1;
135       if (g_package_mask == 0) {
136         // Got a full package, store it.
137         set_timer(1);
138         g_state = STATE_STOR;
139       }
140       break;
141     }
142
143     case STATE_STOR: {
144       // Store byte, but skip start byte.
145       if (g_package_index != -1) {
146         //gg_buffer_gs[g_package_index] = g_package_buffer;
147       }
148       // Next byte.
149       g_package_index++;
150
151       // Wait for next package or next frame.
152       if (g_package_index != 512) {
153         set_trigger_falling();
154         g_state = STATE_MARK;
155       }
156       else {
157         set_timer(20);
158         g_state = STATE_IDLE;
159       }
160       break;
161     }
162
163     default: {
164       break;
165     }
166   }
167 }
168
169
170 void dmx_int_ext(void)
171 {
172   // Disable this interrupt.
173   set_trigger_off();
174
175   switch (g_state)
176   {
177     case STATE_IDLE: {
178       // Wait for end of Reset.
179       set_timer(88);
180       set_trigger_rising();
181       g_state = STATE_WAIT;
182       break;
183     }
184
185     case STATE_WAIT: {
186       // We got a stray edge before Reset timeout, back to IDLE.
187       set_timer(1);
188       g_state = STATE_IDLE;
189       break;
190     }
191
192     case STATE_MARK: {
193       // We got our start bit, sync to middle.
194       mcu_debug();
195       set_timer(2);
196       g_state = STATE_SYNC;
197       break;
198     }
199
200     default: {
201       break;
202     }
203   }
204 }
205