turn ftdi driver into echo server
[goodfet] / firmware / apps / radios / atmel_radio.c
1 /*! \file atmel_radio.c
2   \author bx forked from neighbor Travis Goodspeed
3   \brief Atmel Radio Register Interface
4
5 */
6
7 //Higher level left to client application.
8
9 #include "platform.h"
10 #include "command.h"
11
12 #include "atmel_radio.h"
13 #include "spi.h"
14
15 uint8_t AACK_enabled;
16
17 //! Handles a Chipcon SPI command.
18 void atmel_radio_handle_fn( uint8_t const app,
19                             uint8_t const verb,
20                             uint32_t const datalen32);
21
22 // define the atmel_radio app's app_t
23 app_t const atmel_radio_app = {
24
25   /* app number */
26   ATMEL_RADIO,
27
28   /* handle fn */
29   atmel_radio_handle_fn,
30
31   /* name */
32   "ATMEL_RADIO",
33
34   /* desc */
35   "\tThe ATMEL_RADIO app adds support for the atmel radio.\n"
36 };
37
38 #define TRX_REGISTER_BASEADDR 0x140
39 inline void reg_write(u16 addr, u8 val)
40 {
41   *(u8*)(TRX_REGISTER_BASEADDR + addr) = val;
42 }
43
44 inline u8 reg_read(u16 addr)
45 {
46   return *(u8*)(TRX_REGISTER_BASEADDR + addr);
47 }
48
49 inline void reg_bit_write(u16 addr, u8 pos, u8 value)
50 {
51   u8 old, mask;
52   mask = ~(1 << pos);
53   old = reg_read(addr) & ~mask; //bits to keep
54   old = old | (value << pos); //bit to add
55   reg_write(addr, old); //write byte
56 }
57
58 void atmel_radio_clear_frame_buffer() {
59   TRXFBST = 0; //reset the frame buffer pointer to signal it was read (resets the PHR - length value)
60 }
61
62
63 u16 atmel_radio_set_state(u8 state) //based on zigduino-radio, radio_rfa.c
64 {
65   u8 cmd, retries;
66   /* ensure not in state transition */
67   while (STATE_TRANSITION_IN_PROGRESS == (STATE_TRANSITION_IN_PROGRESS &TRX_STATE)) {}
68   switch(state) {
69   case TRX_OFF:
70     cmd = CMD_TRX_OFF;
71     break;
72   case PLL_ON:
73     cmd = CMD_PLL_ON;
74     break;
75   case BUSY_TX:
76     cmd = CMD_TX_START;
77     break;
78   case RX_ON:
79   default: 
80     if (AACK_enabled) {
81       cmd =  CMD_RX_AACK_ON;
82       state = RX_AACK_ON;
83     } else {
84       cmd = CMD_RX_ON;
85     }
86     break;
87   }
88
89   TRX_STATE = cmd;
90   retries = 180; // enough to receive ongoing frame
91   do {
92     if (state == (state & TRX_STATUS)) {
93       break;
94     }
95     retries--;
96     _delay_ms(32);
97   } while (retries);
98   if (state != (state & TRX_STATUS)) {
99     return (state & TRX_STATUS);
100   }else{
101     return 0;
102   }
103 }
104
105 u16 atmel_radiosetup(){
106   u16 status;
107   /* initialize transceiver
108      code based on zigduino-radio
109   */
110   //TRX_RESET_LOW
111   TRXPR &= ~(1 << TRXRST);
112
113   //TRX_SLPTR_LOW.  Make sure radio isn't sleeping
114   TRXPR  &= ~(1 << SLPTR);
115
116   _delay_ms(6/1000.0);
117   //TRX_RESET_HIGH
118   TRXPR |= (1 << TRXRST);
119
120   /* disable IRQ and clear any pending IRQs */
121   {
122     IRQ_MASK = 0;
123     /* clear IRQ history by reading status*/
124     status = IRQ_STATUS;
125   }
126   atmel_radio_set_state(TRX_OFF);
127
128   /* setup options for extended operating sniffing mode */
129   
130   // disable auto ack
131   CSMA_SEED_1 &= 0xEF & ~(1 << AACK_DIS_ACK); 
132   
133   // disable filtering of reserved frame types and reserve frame type processing
134   XAH_CTRL_1 &= 0xDF & ~(1 << AACK_FLTR_RES_FT);
135   XAH_CTRL_1 &= 0xEF & ~(1 << AACK_UPLD_RES_FT);
136   
137   // enable promiscuous mode
138   XAH_CTRL_1 |= 1 << AACK_PROM_MODE;
139
140   
141   // disable frame protection
142   TRX_CTRL_2 &= 0x7F &  ~(1 << RX_SAFE_MODE);
143
144   // unset auto crc
145   TRX_CTRL_1 &= 0xDF & ~(1 << TX_AUTO_CRC_ON);
146
147
148   atmel_radio_clear_frame_buffer();
149
150   // extended operation mode disabled by default
151   AACK_enabled = 0;
152
153
154   /* enter RX_ON state */
155   return atmel_radio_set_state(RX_ON);
156
157 }
158
159
160 void atmel_radio_pokebyte(u16 addr, u8 data) {
161   reg_write(addr, data);
162 }
163
164 u8 atmel_radio_peekbyte(u16 addr) {
165   return reg_read(addr);
166 }
167
168 //! Writes bytes into the Atmel's ram
169 void atmel_radio_pokeram(u16 addr, u8 *data, u16 len){
170   u16 i;
171   for (i = 0; i < len; i++ ) {
172     atmel_radio_pokebyte(addr+i, data[i]);
173   }
174 }
175
176 //! Read bytes from the Atmel's RAM.
177 void atmel_radio_peekram(u16 addr, u8 *data, u16 len){
178   u16 i;
179   //Data goes here.
180   for (i = 0; i < len; i++){
181     *data++=atmel_radio_peekbyte(addr+i);
182   }
183 }
184
185 int atmel_radio_is_frame_buffer_empty() {
186   return 0 == TRXFBST;
187 }
188
189
190 void atmel_radio_handle_fn( uint8_t const app,
191                             uint8_t const verb,
192                             uint32_t const datalen32){
193
194   // cmddata -> byte
195   // cmddataword -> int
196   // cmddatalong -> long
197   u16 readlen16;
198   u16 ret;
199   u8 retries;
200   uint8_t framelen8;
201   switch(verb){
202   case PEEK:
203     //case READ:
204     readlen16 = cmddataword[1]; // Backup length. Second byte
205     atmel_radio_peekram(cmddataword[0], // First word is address
206                         cmddata, // Return in same buffer
207                         readlen16); // length
208     txdata(app,verb,readlen16);
209     break;
210     //case WRITE:
211   case POKE:
212     atmel_radio_pokeram(cmddataword[0], // First word is address
213                         cmddata+2,  // Remainder of buffer is data
214                         (u16) datalen32-2); //Length implied by packet length
215     txdata(app,verb, datalen32-2); //return number of poked bytes
216     break;
217   case SETUP:
218     ret = atmel_radiosetup();
219     txdata(app, verb, ret);
220     break;
221
222   case ATMEL_RADIO_RX:
223     // ensure radio is not in the middle or receiving a packet
224     atmel_radio_set_state(RX_ON);
225     // set state to PLL_ON so frame buffer isn't clobbered
226     atmel_radio_set_state(PLL_ON);
227
228     if (!atmel_radio_is_frame_buffer_empty()) { //only if we recieved something new
229       framelen8 = TST_RX_LENGTH; //register contains frame length
230       if  ((framelen8 > 127) ) { //frame too big
231         framelen8 = 127;
232       }
233       memcpy(cmddata, (void *) &TRXFBST, framelen8); //return in same buffer
234       atmel_radio_clear_frame_buffer();
235     } else {
236       framelen8 = 0; //didn't receive anything new
237     }
238     // receive packets again
239     atmel_radio_set_state(RX_ON);
240
241     txdata(app, verb, framelen8);
242     break;
243   case ATMEL_RADIO_TX:
244     //prevent radio from recieving new packets
245     atmel_radio_set_state(PLL_ON);
246     uint8_t maxlen = 127;
247     if (cmddata[0] > maxlen) { //truncate too long packets
248       cmddata[0] = maxlen;
249     }
250
251     memcpy((void *) &TRXFBST, cmddata, datalen32); //copy length + packet
252     atmel_radio_set_state(BUSY_TX); //send packet
253
254
255     while (PLL_ON != (PLL_ON & TRX_STATUS)) {} //wait for TX done
256     //reset the frame buffer pointer to signal it was read
257     atmel_radio_clear_frame_buffer();
258     atmel_radio_set_state(RX_ON);
259     txdata(app, verb, 0);
260
261     break;
262   case ATMEL_RADIO_AACK_ON:
263     if (!AACK_enabled) {
264       AACK_enabled = 1;
265       /* enter PLL_ON state */
266       atmel_radio_set_state(PLL_ON);
267       /* enter RX_ON state */
268       atmel_radio_set_state(RX_ON);
269     }
270     txdata(app, verb, 0);
271     break;
272   case ATMEL_RADIO_AACK_OFF:
273     if (AACK_enabled) {
274       AACK_enabled = 0;
275       /* enter PLL_ON state */
276       atmel_radio_set_state(PLL_ON);
277       /* enter RX_ON state */
278       atmel_radio_set_state(RX_ON);
279     }
280     txdata(app, verb, 0);
281     break;
282   case ATMEL_RADIO_AUTOCRC_ON:
283     if (0 == (TRX_CTRL_1 & (1 << TX_AUTO_CRC_ON))) { //not enabled
284       atmel_radio_set_state(TRX_OFF);
285       // can only be safely set in TRX_OFF mode
286       TRX_CTRL_1 |= 1 << TX_AUTO_CRC_ON;
287       atmel_radio_set_state(RX_ON);
288     }
289
290     txdata(app, verb, 0);
291     break;
292   case ATMEL_RADIO_AUTOCRC_OFF:
293     if (TRX_CTRL_1 & (1 << TX_AUTO_CRC_ON)) { //enabled
294       atmel_radio_set_state(TRX_OFF);
295       // can only be safely set in TRX_OFF mode
296       TRX_CTRL_1 &= 0xDF & ~(1 << TX_AUTO_CRC_ON);
297       atmel_radio_set_state(RX_ON);
298     }
299     txdata(app, verb, 0);
300     break;
301   default:
302     debugstr("Not yet supported in ATMEL_RADIO");
303     txdata(app,verb,-1);
304     break;
305   }
306
307 }