Added basic firmware and client support for the zigduino/atmel128rfa1. It can now...
[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 #include <stdlib.h> //added for itoa
12
13 #include "atmel_radio.h"
14 #include "spi.h"
15
16 //! Handles a Chipcon SPI command.
17 void atmel_radio_handle_fn( uint8_t const app,
18                             uint8_t const verb,
19                             uint32_t const len);
20
21 // define the atmel_radio app's app_t
22 app_t const atmel_radio_app = {
23
24   /* app number */
25   ATMEL_RADIO,
26
27   /* handle fn */
28   atmel_radio_handle_fn,
29
30   /* name */
31   "ATMEL_RADIO",
32
33   /* desc */
34   "\tThe ATMEL_RADIO app adds support for the atmel radio.\n"
35 };
36
37 #define TRX_REGISTER_BASEADDR 0x140
38 inline void reg_write(u16 addr, u8 val)
39 {
40   *(u8*)(TRX_REGISTER_BASEADDR + addr) = val;
41 }
42
43 inline u8 reg_read(u16 addr)
44 {
45   return *(u8*)(TRX_REGISTER_BASEADDR + addr);
46 }
47 inline void reg_bit_write(u16 addr, u8 pos, u8 value)
48 {
49   u8 old, mask;
50   mask = ~(1 << pos);
51   old = reg_read(addr) & ~mask; //bits to keep
52   old = old | (value << pos); //bit to add
53   reg_write(addr, old); //write byte
54 }
55
56
57 void atmel_radio_set_state(u8 state) //based on zigduino-radio, radio_rfa.c
58 {
59   u8 cmd, retries;
60   /* ensure not in state transition */
61   while (STATE_TRANSITION_IN_PROGRESS == (STATE_TRANSITION_IN_PROGRESS &TRX_STATE)) {}
62   switch(state) {
63   case TRX_OFF:
64     cmd = CMD_TRX_OFF;
65     break;
66   case PLL_ON:
67     cmd = CMD_PLL_ON;
68     break;
69   case BUSY_TX:
70     cmd = CMD_TX_START;
71     break;
72   default: //doesn't exist
73     cmd = CMD_RX_ON;
74     break;
75   }
76
77   TRX_STATE = cmd;
78   retries = 140; /* enough to receive ongoing frame */
79   do {
80     if (state == (state & TRX_STATUS)) {
81       break;
82     }
83     retries--;
84     _delay_ms(32);
85   } while (retries);
86 }
87
88 void atmel_radiosetup(){
89   u8 status;
90   /* initialize transceiver
91      code based on zigduino-radio
92   */
93   //TRX_RESET_LOW
94   TRXPR &= ~(1 << TRXRST);
95
96   //TRX_SLPTR_LOW.  Make sure radio isn't sleeping
97   TRXPR  &= ~(1 << SLPTR);
98
99   _delay_ms(6/1000.0);
100   //TRX_RESET_HIGH
101   TRXPR |= (1 << TRXRST);
102
103   /* disable IRQ and clear any pending IRQs */
104   {
105     IRQ_MASK = 0;
106     /* clear IRQ history by reading status*/
107     status = IRQ_STATUS;
108   }
109
110   // unset auto crc
111   TRX_CTRL_1 &= 0xDF & ~(1 << TX_AUTO_CRC_ON);
112
113   /* enter TRX_OFF state */
114   atmel_radio_set_state(TRX_OFF);
115
116   /* enter RX_ON state */
117   atmel_radio_set_state(RX_ON);
118
119 }
120
121
122 void atmel_radio_pokebyte(u16 addr, u8 data) {
123   reg_write(addr, data);
124 }
125
126 u8 atmel_radio_peekbyte(u16 addr) {
127   return reg_read(addr);
128 }
129
130 //! Writes bytes into the Atmel's ram
131 void atmel_radio_pokeram(u16 addr, u8 *data, u16 len){
132   u16 i;
133   for (i = 0; i < len; i++ ) {
134     atmel_radio_pokebyte(addr+i, data[i]);
135   }
136 }
137
138 //! Read bytes from the Atmel's RAM.
139 void atmel_radio_peekram(u16 addr, u8 *data, u16 len){
140   u16 i;
141   //Data goes here.
142   for (i = 0; i < len; i++){
143     *data++=atmel_radio_peekbyte(addr+i);
144   }
145 }
146
147 int atmel_radio_is_frame_buffer_empty() {
148   return TRXFBST == 0;
149 }
150
151 void atmel_radio_clear_frame_buffer() {
152   TRXFBST = 0; //reset the frame buffer pointer to signal it was read
153 }
154
155 //! Handles a Chipcon SPI command.
156 void atmel_radio_handle_fn( uint8_t const app,
157                             uint8_t const verb,
158                             uint32_t const len){
159
160   u16 length;
161   u8  len8;
162
163   switch(verb){
164   case PEEK:
165
166   case READ:
167     length=cmddataword[1]; // Backup length. Second byte
168     atmel_radio_peekram(cmddataword[0], // First word is address
169                         cmddata, // Return in same buffer
170                         length);
171     txdata(app,verb,length);
172     break;
173   case WRITE:
174   case POKE:
175     atmel_radio_pokeram(cmddataword[0], // First word is address
176                         cmddata+2,  // Remainder of buffer is data
177                         len-2); //Length implied by packet length
178     txdata(app,verb,len-2); //return number of poked bytes
179     break;
180   case SETUP:
181     atmel_radiosetup();
182     txdata(app,verb,0);
183     break;
184
185   case ATMEL_RADIO_RX:
186
187     // set to PLL_ON so frame buffer isn't clobbered
188     atmel_radio_set_state(PLL_ON);
189     len8 = 8;
190     if (!atmel_radio_is_frame_buffer_empty()) { //only if we recieved something new
191       len8 = TST_RX_LENGTH; //register contains frame length
192
193       if  ((len8 > 0x80) ) { //frame too big
194         txdata(app,verb,0);
195       } else {
196         memcpy(cmddata, (void *) &TRXFBST, len8); //return in same buffer
197         atmel_radio_clear_frame_buffer();
198         txdata(app, verb, len8);
199       }
200     }else{
201       // didn't recieve anything new
202       txdata(app,verb,0);
203     }
204     // receive packets again
205     atmel_radio_set_state(RX_ON);
206
207     break;
208   case ATMEL_RADIO_TX:
209     //prevent radio from recieving new packets
210     atmel_radio_set_state(PLL_ON);
211     if (cmddata[0] > 127) { //truncate too long packets
212       cmddata[0] = 127;
213     }
214
215     memcpy((void *) &TRXFBST, cmddata, cmddata[0]+1); //copy length + packet
216     atmel_radio_set_state(BUSY_TX); //send packet
217
218     while (PLL_ON != (PLL_ON & TRX_STATUS)) {} //wait for TX done
219     //reset the frame buffer pointer to signal it was read
220     atmel_radio_clear_frame_buffer();
221     atmel_radio_set_state(RX_ON);
222     txdata(app, verb, len8);
223
224     break;
225
226   case ATMEL_RADIO_RX_FLUSH:
227   case ATMEL_RADIO_TX_FLUSH:
228   default:
229     debugstr("Not yet supported in ATMEL_RADIO");
230     txdata(app,verb,-1);
231     break;
232   }
233
234 }