Integrating smile's r0ket-nrf24l01-foo. Right now, it compiles.
[cerebrum.git] / cerebrum_firmware.c
blobab18b7bd34a9f3085b3e19b4f9e73cf8108b9be5
1 /*
2 Copyright (C) 2012 jaseg <s@jaseg.de>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 version 3 as published by the Free Software Foundation.
7 */
9 #include <avr/io.h>
10 #include <util/delay.h>
11 #include <avr/pgmspace.h>
12 #include <avr/interrupt.h>
13 #include "uart.h"
15 void setup(void);
16 void loop(void);
18 int main(void){
19 setup();
20 for(;;) loop();
23 void setup(){
24 uart_init(UART_BAUD_SELECT_DOUBLE_SPEED(115200, F_CPU));
25 //s/w "BCM"(<== "Binary Code Modulation") timer setup
27 TCCR0A |= _BV(WGM00)|_BV(WGM01);
28 TCCR0B |= _BV(CS02);
29 TIMSK0 |= _BV(TOIE0);
31 //FIXME set PWM output DDRs
32 //The DDRs of the led matrix outputs are set in the mux loop.
33 sei();
36 //this scary construct is in place to make the compiler happy. if you know a better way, feel free to improve.
37 uint8_t _frameBuffer[] = {0,0,0,0};
38 uint8_t _secondFrameBuffer[] = {0,0,0,0};
39 uint8_t* frameBuffer = _frameBuffer;
40 uint8_t* secondFrameBuffer = _secondFrameBuffer;
41 char nbuf;
42 int state = 0;
43 uint8_t switch_last_state = 0;
44 int switch_debounce_timeout = 0;
45 uint8_t mcnt = 0;
46 uint8_t ccnt = 0;
48 #define PWM_COUNT 5
49 uint8_t pwm_cycle = 0;
50 uint8_t pwm_val[PWM_COUNT];
51 #define INPUT_COUNT 0
52 uint8_t debounce_timeouts[INPUT_COUNT];
53 uint8_t switch_states[INPUT_COUNT];
55 void swapBuffers(void){
56 uint8_t* tmp = frameBuffer;
57 frameBuffer = secondFrameBuffer;
58 secondFrameBuffer = tmp;
61 void setLED(int num, int val){
62 if(num<32){
63 frameBuffer[num>>3] &= ~(1<<(num&7));
64 if(val)
65 frameBuffer[num>>3] |= 1<<(num&7);
69 int parseHex(char* buf){
70 int result = 0;
71 int len = 2;
72 for(int i=0; i<len; i++){
73 char c = buf[len-i];
74 int v = 0;
75 if(c>='0' && c<='9'){
76 v=(c-'0');
77 }else if(c>='a' && c<= 'f'){
78 v=(c-'a'+10);
79 }else if(c>='A' && c<= 'F'){
80 v=(c-'A'+10);
82 result |= v<<(4*i);
84 return result;
87 inline char hex_nibble(uint8_t data){
88 if(data<0xA)
89 return data+'0';
90 else
91 return data+'A'-0xA;
94 void put_hex(uint8_t data){
95 uart_putc(hex_nibble(data&15));
96 uart_putc(hex_nibble(data>>4));
99 void loop(){ //one frame
100 static uint8_t escape_state = 0;
101 uint16_t receive_state = 1;
102 //primitive somewhat messy state machine of the uart interface
103 do{ //Always empty the receive buffer since there are _delay_xxs in the following code and thus this might not run all that often.
104 receive_state = uart_getc();
105 char c = receive_state&0xFF;
106 receive_state &= 0xFF00;
107 //escape code format:
108 // \\ - backslash
109 // \n - newline
110 // \[x] - x
111 //eats three commands: 's' (0x73) led value sets led number [led] to [value]
112 // 'b' (0x62) buffer buffer buffer buffer sets the whole frame buffer
113 // 'a' (0x61) meter value sets analog meter number [meter] to [value]
114 // 'r' (0x72) read the frame buffer
115 //this device will utter a "'c' (0x63) num state" when switch [num] changes state to [state]
116 //commands are terminated by \n
117 if(!receive_state){
118 if(!escape_state){
119 if(c == '\\'){
120 receive_state |= 0x02;
121 escape_state = 1;
122 }else if(c == '\n'){
123 receive_state |= 0x02;
124 state = 0;
126 }else{
127 receive_state = 0;
128 escape_state = 0;
129 switch(c){
130 case '\\':
131 break;
132 case 'n':
133 c = '\n';
134 break;
138 if(!receive_state){
139 switch(state){
140 case 0: //Do not assume anything about the variables used
141 //command char
142 switch(c){
143 case 's':
144 state = 2;
145 break;
146 case 'b':
147 nbuf = 0;
148 state = 4;
149 break;
150 case 'a':
151 state = 5;
152 nbuf = 0;
153 break;
154 case 'r':
155 uart_putc('r');
156 for(uint8_t i=0; i<sizeof(frameBuffer); i++){
157 put_hex(frameBuffer[i]);
159 uart_putc('\n');
160 break;
162 break;
163 case 2:
164 nbuf=c;
165 state = 3;
166 break;
167 case 3:
168 setLED(nbuf, c);
169 state = 0;
170 break;
171 case 4:
172 secondFrameBuffer[(uint8_t) nbuf] = c;
173 nbuf++;
174 if(nbuf == 4){
175 swapBuffers();
176 state = 0;
178 break;
179 case 5:
180 if(c > PWM_COUNT)
181 c = 0;
182 nbuf = c;
183 state = 6;
184 break;
185 case 6:
186 pwm_val[(uint8_t) nbuf] = c;
187 state = 0;
190 }while(!receive_state);
191 for(int i=0; i<8; i++){
192 uint8_t Q = 0x80>>i; //select the currently active "row" of the matrix. On the protoboards I make, this actually corresponds to physical traces.
193 //uint8_t DDRQ = 0xFF>>i; //This is supposed to be an optimization. It is untested and will probably not work.
194 uint8_t DDRQ = 0xFF; //Just for testing: reactivating the old behavioor
195 //unpacking of frame data: data is packed like this: [11111117][22222266][33333555][4444----]
196 if(!(i&4))
197 Q |= frameBuffer[i&3] >> i;
198 else
199 Q |= frameBuffer[i&3] & (0xFF << (i&3));
200 //FIXME this whole mapping shit should be done in h/w!!1!
201 //FIXME this whole mapping is not even correct!!1!
202 //FIXME IT DOES NOT WORK!!1!
203 // Q&0x01 ==> PG5
204 // 02 ==> PE3
205 // 04 ==> PH3
206 // 08 ==> PH4
207 // 10 ==> PH5
208 // 20 ==> PH6
209 // 40 ==> PB4
210 // 80 ==> PB5
211 DDRG&=~(1<<5);
212 DDRG|=(DDRQ&1)<<5;
213 PORTG&=~(1<<5);
214 PORTG|=(Q&1)<<5;
215 DDRE&=~(1<<3);
216 DDRE|=(DDRQ&2)<<2;
217 PORTE&=~(1<<3);
218 PORTE|=(Q&2)<<2;
219 DDRH&=0xC3;
220 DDRH|=(DDRQ&0x3C);
221 PORTH&=0xC3;
222 PORTH|=(Q&0x3C);
223 DDRB&=0xCF;
224 DDRB|=(DDRQ&0xC0)>>2;
225 PORTB&=0xCF;
226 PORTB|=(Q&0xC0)>>2;
227 /* second channel skeleton
228 Q = 0x80>>i;
229 if(!(i&4))
230 Q |= frameBuffer[4+(i&3)] >> i;
231 else
232 Q |= frameBuffer[4+(i&3)] & (0xFF << (i&3));
233 DDRA = DDRQ;
234 PORTA = Q;
235 //PORTD &= 0x0F;
236 //PORTD |= Q&0xF0;
237 //PORTB &= 0xF0;
238 //PORTB |= Q&0x0F;
240 _delay_ms(1);
242 /* no switches (yet)
243 switch_states[0] |= !!(PINH&0x02);
244 for(int i=0; i<INPUT_COUNT; i++){
245 debounce_timeouts[i]--;
246 //A #define for the debounce time would be great
247 if(debounce_timeouts[i] == 0){
248 uint8_t new_switch_state = switch_states[i]<<1;
249 if(!(switch_states[i]^new_switch_state)){
250 uart_putc('c');
251 uart_putc(i);
252 uart_putc(switch_states[i]&1);
253 debounce_timeouts[i] = 0xFF;
254 switch_states[i] = new_switch_state&3;
261 //Software PWM stuff
262 //Called every 256 cpu clks (i.e should not get overly long)
263 ISR(TIMER0_OVF_vect){
264 uint8_t Q = 0;
265 Q |= (pwm_val[0] & pwm_cycle);
266 Q |= (pwm_val[1] & pwm_cycle)?2:0;
267 Q |= (pwm_val[2] & pwm_cycle)?4:0;
268 Q |= (pwm_val[3] & pwm_cycle)?8:0;
269 Q |= (pwm_val[4] & pwm_cycle)?16:0;
270 PORTC = Q;
271 OCR0A = pwm_cycle;
272 pwm_cycle<<=1;
273 if(!pwm_cycle)
274 pwm_cycle = 1;