Rename foo_start to foo_exec, introduce one for DMX.
[dmxpainter.git] / src / dmx.c
1 #include "dmx.h"
2
3 #include "mcu.h"
4
5 #include "buffer.h"
6
7
8 void enable_timer(int8_t us)
9 {
10   // Prepare timer counter.
11   TCNT0 = 0xFF - 2 * us;
12
13   // Enable timer, use a frequency prescaler of 8 (p72).
14   bits_mask_on(TCCR0, (1 << CS01));
15 }
16
17 void disable_timer(void)
18 {
19   // Disable timer (p72).
20   bits_mask_off(TCCR0, (1 << CS02) | (1 << CS01) | (1 << CS00));
21 }
22
23
24 void enable_trigger(void)
25 {
26   // Enable interrupt triggered by edge on pin.
27   bits_on(GICR, INT0);
28 }
29
30 void disable_trigger(void)
31 {
32   // Disable interrupt triggered by edge on pin.
33   bits_off(GICR, INT0);
34 }
35
36 void enable_usart(void)
37 {
38   // Enable RXD.
39   bits_on(UCSRB, RXEN);
40 }
41
42 void disable_usart(void)
43 {
44   // Disable RXD.
45   bits_off(UCSRB, RXEN);
46 }
47
48 ///////////////////////////////
49
50 void dmx_init(void)
51 {
52   // Configure both pins as input.
53   pin_in(PIN_DMX_INT);
54   pin_in(PIN_DMX_RXD);
55
56   // Initialize USART (p156) with
57   // 250kbaud    (UBRR = 3),
58   // 8 data bits (UCSZ = 011),
59   // 2 stop bits (USBS = 1),
60   // no parity   (UPM  = 00).
61   UBRRL = F_CPU / (16 * 250e3) - 1;
62   UBRRH = (0 << URSEL) | 0;
63   UCSRC = (1 << URSEL)
64         | bits_value(UCSZ1) | bits_value(UCSZ0)
65         | bits_value(USBS);
66   // Enable USART RXD interrupt (and clear UCSZ2 and *XEN).
67   UCSRB = bits_value(RXCIE);
68
69   // Enable timer interrupt (p72).
70   bits_on(TIMSK, TOIE0);
71
72   // Trigger INT0 on any edge (ISC0 = 01, p67).
73   bits_on(MCUCR, ISC00);
74 }
75
76 void dmx_exec(void)
77 {
78   // Just enable the trigger for the pin.
79   enable_trigger();
80 }
81
82 ///////////////////////////////
83
84 enum {
85   STATE_IDLE,
86   STATE_SYNC,
87   STATE_WAIT,
88   STATE_RECV,
89   STATE_STOR
90 } g_state;
91 int16_t g_index;
92
93
94 void dmx_int_timer0_ovf(void)
95 {
96   // Disable this interrupt.
97   disable_timer();
98
99   switch (g_state) {
100     case STATE_SYNC: {
101       // Line was low for 88 us, all is fine.
102       //mcu_debug_off();
103       g_state = STATE_WAIT;
104       break;
105     }
106     case STATE_RECV:
107     case STATE_STOR: {
108       // We got a timeout, back to Idle.
109       disable_usart();
110       enable_trigger();
111       g_state = STATE_IDLE;
112       break;
113     }
114     default: {
115       break;
116     }
117   }
118   
119 }
120
121 void dmx_int_ext(void)
122 {
123   switch (g_state) {
124     case STATE_IDLE: {
125       // Only trigger on fallen edge.
126       if (!pin_is_set(PIN_DMX_RXD)) {
127         // Wait for 88 us.
128         enable_timer(88);
129         mcu_debug_off();
130         //mcu_debug_on();
131         g_state = STATE_SYNC;
132       }
133       break;
134     }
135     case STATE_SYNC: {
136       // Got a stray edge while Reset, back to Idle.
137       disable_timer();
138       //mcu_debug_off();
139       g_state = STATE_IDLE;
140       break;
141     }
142     case STATE_WAIT: {
143       // This edge is the Mark, start the USART and disable
144       // this interrupt.
145       disable_trigger();
146       enable_usart();
147             mcu_debug_on();      mcu_debug_off();
148       g_state = STATE_RECV;
149       break;
150     }
151     default: {
152       break;
153     }
154   }
155 }
156
157 void dmx_int_usart_rxc(void)
158 {
159   // Read USART data (p146).
160   uint8_t rxd;
161   uint8_t err;
162   // Read Frame Error flag.
163   err = UCSRA & bits_value(FE);
164   // Read data byte (and clear RXC flag).
165   rxd = UDR;
166         
167   if (err) {
168   mcu_debug_on();      mcu_debug_off();
169     goto last;
170   }
171
172   switch (g_state) {
173     case STATE_RECV: {
174       // Check for valid start byte.
175       //if (rxd & (1 << 0)) { mcu_debug_on(); } else { mcu_debug_off(); }
176       /*if (rxd != 0x00) {
177         goto last;
178       }*/
179       
180       // Switch to data storage.
181       g_index = 0;
182       g_state = STATE_STOR;
183       break;
184     }
185     case STATE_STOR: {
186       // Write byte to buffer.
187       gg_buffer_gs[g_index] = rxd;
188       // Next index.
189       g_index++;
190       if (g_index == 512) {
191         goto last;
192       }
193       break;
194     }
195     default: {
196       break;
197     }
198   }
199
200   return;
201 last:
202   // Either an invalid or the last frame appeared, stop DMX.
203   disable_usart();
204   enable_trigger();
205   g_state = STATE_IDLE;
206   return;
207 }