Added TODOs about buf size not based on N_PAINTER.
[dmxpainter.git] / src / dmx.c
1 #include "dmx.h"
2
3 #include "mcu.h"
4
5 #include "buf.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   // But explicitly disable it for now.
75   disable_trigger();
76 }
77
78 void dmx_exec(void)
79 {
80   // Just enable the trigger for the pin.
81   enable_trigger();
82 }
83
84 ///////////////////////////////
85
86 static enum state {
87   STATE_IDLE,
88   STATE_SYNC,
89   STATE_WAIT,
90   STATE_RECV,
91   STATE_STOR
92 };
93 static volatile enum state state_;
94 static          int16_t index_;
95
96
97 void dmx_int_timer0_ovf(void)
98 {
99   // Disable this interrupt.
100   disable_timer();
101
102   switch (state_) {
103     case STATE_SYNC: {
104       // Line was low for 88 us, all is fine.
105       state_ = STATE_WAIT;
106       break;
107     }
108     case STATE_RECV:
109     case STATE_STOR: {
110       // We got a timeout, back to Idle.
111       disable_usart();
112       enable_trigger();
113       state_ = STATE_IDLE;
114       break;
115     }
116     default: {
117       break;
118     }
119   }
120   
121 }
122
123 void dmx_int_ext(void)
124 {
125   switch (state_) {
126     case STATE_IDLE: {
127       // Only trigger on fallen edge.
128       if (!pin_is_set(PIN_DMX_RXD)) {
129         // Wait for 88 us.
130         enable_timer(88);;
131         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       state_ = STATE_IDLE;
139       break;
140     }
141     case STATE_WAIT: {
142       // This edge is the Mark, start the USART and disable
143       // this interrupt.
144       disable_trigger();
145       enable_usart();
146       state_ = STATE_RECV;
147       break;
148     }
149     default: {
150       break;
151     }
152   }
153 }
154
155 void dmx_int_usart_rxc(void)
156 {
157   // Read USART data (p146).
158   uint8_t rxd;
159   uint8_t err;
160   // Read Frame Error flag.
161   err = UCSRA & bits_value(FE);
162   // Read data byte (and clear RXC flag).
163   rxd = UDR;
164   if (err) {
165     goto last;
166   }
167
168   switch (state_) {
169     case STATE_RECV: {
170       // TODO: Check for valid start byte.
171       /*if (rxd != 0x00) {
172         goto last;
173       }*/
174
175       // Switch to data storage.
176       index_ = 0;
177       state_ = STATE_STOR;
178       break;
179     }
180     case STATE_STOR: {
181       // Write byte to buffer.
182       buf_gs__[index_] = rxd;
183       // Next index.
184       index_++;
185       // TODO: Don't store more data than necessary.
186       if (index_ == 512) {
187         goto last;
188       }
189       break;
190     }
191     default: {
192       break;
193     }
194   }
195
196   return;
197 last:
198   // Either an invalid or the last frame appeared, stop DMX.
199   disable_usart();
200   enable_trigger();
201   state_ = STATE_IDLE;
202   return;
203 }