2 * Copyright © 2012 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 #include <ao_radio_spi.h>
21 #include <ao_radio_cmac.h>
23 static __xdata struct ao_radio_spi_reply ao_radio_spi_reply;
24 static __xdata struct ao_radio_spi_request ao_radio_spi_request;
25 static volatile __xdata uint8_t ao_radio_wait_mode;
26 static volatile __xdata uint8_t ao_radio_done = 0;
27 static volatile __xdata uint8_t ao_radio_ready = 1;
28 static __xdata uint8_t ao_radio_mutex;
29 static __xdata uint8_t ao_radio_aes_seq;
31 __xdata int8_t ao_radio_cmac_rssi;
34 #define PRINTD(...) do { printf ("\r%5u %s: ", ao_tick_count, __func__); printf(__VA_ARGS__); flush(); } while(0)
42 if (ao_gpio_get(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN, AO_RADIO_INT)) {
44 ao_wakeup((void *) &ao_radio_ready);
47 ao_wakeup((void *) &ao_radio_done);
52 ao_radio_master_start(void)
54 ao_spi_get_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS,
60 ao_radio_master_stop(void)
62 ao_spi_put_bit(AO_RADIO_CS_PORT, AO_RADIO_CS_PIN, AO_RADIO_CS,
67 ao_radio_master_send(void)
71 PRINTD("send %d\n", ao_radio_spi_request.len);
74 /* Wait for radio chip to be ready for a command
77 PRINTD("Waiting radio ready\n");
78 ao_arch_block_interrupts();
79 ao_radio_ready = ao_gpio_get(AO_RADIO_INT_PORT,
80 AO_RADIO_INT_PIN, AO_RADIO_INT);
82 while (!ao_radio_ready) {
83 ret = ao_sleep((void *) &ao_radio_ready);
87 ao_arch_release_interrupts();
91 PRINTD("radio_ready %d radio_done %d\n", ao_radio_ready, ao_radio_done);
95 ao_radio_wait_mode = 0;
96 ao_radio_master_start();
97 ao_spi_send(&ao_radio_spi_request,
98 ao_radio_spi_request.len,
100 ao_radio_master_stop();
101 PRINTD("waiting for send done %d\n", ao_radio_done);
102 ao_arch_block_interrupts();
103 while (!ao_radio_done)
104 if (ao_sleep((void *) &ao_radio_done))
106 ao_arch_release_interrupts();
107 PRINTD ("sent, radio done %d isr_0 %d isr_1 %d\n", ao_radio_done, isr_0_count, isr_1_count);
108 return ao_radio_done;
112 ao_radio_get(uint8_t req, uint8_t len)
115 ao_mutex_get(&ao_radio_mutex);
116 ao_radio_spi_request.len = AO_RADIO_SPI_REQUEST_HEADER_LEN + len;
117 ao_radio_spi_request.request = req;
118 ao_radio_spi_request.setting = ao_config.radio_setting;
124 ao_mutex_put(&ao_radio_mutex);
128 ao_radio_get_data(__xdata void *d, uint8_t size)
131 ao_radio_master_start();
132 ao_spi_recv(&ao_radio_spi_reply,
133 AO_RADIO_SPI_REPLY_HEADER_LEN + size,
135 ao_radio_master_stop();
136 ao_xmemcpy(d, ao_radio_spi_reply.payload, size);
137 PRINTD ("fetched %d\n", size);
141 ao_radio_recv_abort(void)
143 ao_radio_get(AO_RADIO_SPI_RECV_ABORT, 0);
144 ao_radio_master_send();
149 ao_radio_send(const void *d, uint8_t size)
151 ao_radio_get(AO_RADIO_SPI_SEND, size);
152 ao_xmemcpy(&ao_radio_spi_request.payload, d, size);
153 ao_radio_master_send();
159 ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)
167 ao_radio_get(AO_RADIO_SPI_RECV, 0);
168 ao_radio_spi_request.recv_len = size;
169 ao_radio_spi_request.timeout = timeout;
170 recv = ao_radio_master_send();
173 ao_radio_recv_abort();
176 ao_radio_get_data(d, size);
177 recv = ao_radio_spi_reply.status;
184 ao_radio_cmac_set_key(void)
186 if (ao_radio_aes_seq == ao_config_aes_seq)
190 PRINTD ("set key\n");
191 ao_radio_get(AO_RADIO_SPI_CMAC_KEY, AO_AES_LEN);
192 ao_xmemcpy(&ao_radio_spi_request.payload, &ao_config.aes_key, AO_AES_LEN);
193 ao_radio_master_send();
195 PRINTD ("key set\n");
196 ao_radio_aes_seq = ao_config_aes_seq;
200 ao_radio_cmac_send(__xdata void *packet, uint8_t len) __reentrant
202 if (len > AO_CMAC_MAX_LEN)
203 return AO_RADIO_CMAC_LEN_ERROR;
205 ao_radio_cmac_set_key();
207 PRINTD ("cmac_send: send %d\n", len);
212 PRINTD ("sending packet\n");
213 ao_radio_get(AO_RADIO_SPI_CMAC_SEND, len);
214 ao_xmemcpy(&ao_radio_spi_request.payload, packet, len);
215 ao_radio_master_send();
217 PRINTD ("packet sent\n");
218 return AO_RADIO_CMAC_OK;
222 ao_radio_cmac_recv(__xdata void *packet, uint8_t len, uint16_t timeout) __reentrant
227 if (len > AO_CMAC_MAX_LEN)
228 return AO_RADIO_CMAC_LEN_ERROR;
230 ao_radio_cmac_set_key();
234 PRINTD ("queuing recv\n");
235 ao_radio_get(AO_RADIO_SPI_CMAC_RECV, 0);
236 ao_radio_spi_request.recv_len = len;
237 ao_radio_spi_request.timeout = timeout;
238 recv = ao_radio_master_send();
239 PRINTD ("recv queued: %d\n", recv);
242 ao_radio_recv_abort();
243 return AO_RADIO_CMAC_TIMEOUT;
246 PRINTD ("fetching data\n");
247 ao_radio_get_data(packet, len);
248 recv = ao_radio_spi_reply.status;
249 ao_radio_cmac_rssi = ao_radio_spi_reply.rssi;
251 PRINTD ("data fetched: %d %d\n", recv, ao_radio_cmac_rssi);
255 static uint8_t ao_radio_test_on;
258 ao_radio_test(uint8_t on)
261 if (!ao_radio_test_on) {
262 ao_radio_get(AO_RADIO_SPI_TEST_ON, 0);
263 ao_radio_test_on = 1;
264 ao_radio_master_send();
267 if (ao_radio_test_on) {
268 ao_radio_spi_request.len = AO_RADIO_SPI_REQUEST_HEADER_LEN;
269 ao_radio_spi_request.request = AO_RADIO_SPI_TEST_OFF;
270 ao_radio_master_send();
271 ao_radio_test_on = 0;
278 ao_radio_test_cmd(void)
282 if (ao_cmd_lex_c != '\n') {
284 mode = (uint8_t) ao_cmd_lex_u32;
290 printf ("Hit a character to stop..."); flush();
298 __code struct ao_cmds ao_radio_cmds[] = {
299 { ao_radio_test_cmd, "C <1 start, 0 stop, none both>\0Radio carrier test" },
306 ao_spi_init_cs(AO_RADIO_CS_PORT, (1 << AO_RADIO_CS_PIN));
308 ao_enable_port(AO_RADIO_INT_PORT);
309 ao_exti_setup(AO_RADIO_INT_PORT,
311 AO_EXTI_MODE_RISING|AO_EXTI_MODE_FALLING,
313 ao_exti_enable(AO_RADIO_INT_PORT, AO_RADIO_INT_PIN);
314 ao_cmd_register(&ao_radio_cmds[0]);