2 * Copyright © 2009 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.
20 static __xdata struct ao_packet_recv rx_packet;
21 static __xdata struct ao_packet tx_packet;
22 static __xdata char tx_data[AO_PACKET_MAX];
23 static __xdata char rx_data[AO_PACKET_MAX];
24 static __pdata uint8_t rx_len, rx_used, tx_used;
25 static __pdata uint8_t rx_seq;
27 static __xdata uint16_t ao_packet_timer_delay;
28 static __xdata uint8_t ao_packet_timer_cancelled;
30 static __xdata struct ao_task ao_packet_task;
31 static __xdata struct ao_task ao_packet_timer_task;
32 static __xdata uint8_t ao_packet_enable;
33 static __xdata uint8_t ao_packet_master_sleeping;
36 ao_packet_timer(void) __reentrant
40 while (ao_packet_enable) {
42 /* wait until the timer task is needed
44 while (!ao_packet_timer_delay && ao_packet_enable)
45 ao_sleep(&ao_packet_timer_delay);
47 delay = ao_packet_timer_delay;
48 ao_packet_timer_delay = 0;
50 /* pause waiting for either a timeout or
55 /* if not canceled, abort the receive
57 if (!ao_packet_timer_cancelled) {
58 printf ("packet timeout\n"); flush();
59 ao_radio_abort(AO_DMA_TIMEOUT);
66 ao_packet_timer_set(uint16_t delay)
68 ao_packet_timer_delay = delay;
69 ao_packet_timer_cancelled = 0;
70 ao_wakeup(&ao_packet_timer_delay);
74 ao_packet_timer_cancel(void)
76 ao_packet_timer_cancelled = 1;
77 ao_packet_timer_delay = 0;
78 ao_wake_task(&ao_packet_timer_task);
85 ao_mutex_get(&ao_radio_mutex);
87 RF_CHANNR = ao_config.radio_channel;
88 ao_dma_set_transfer(ao_radio_dma,
91 sizeof (struct ao_packet),
93 DMA_CFG0_TMODE_SINGLE |
94 DMA_CFG0_TRIGGER_RADIO,
97 DMA_CFG1_PRIORITY_HIGH);
98 ao_dma_start(ao_radio_dma);
100 __critical while (!ao_radio_dma_done)
101 ao_sleep(&ao_radio_dma_done);
102 ao_mutex_put(&ao_radio_mutex);
111 ao_mutex_get(&ao_radio_mutex);
113 RF_CHANNR = ao_config.radio_channel;
114 ao_dma_set_transfer(ao_radio_dma,
117 sizeof (struct ao_packet_recv),
118 DMA_CFG0_WORDSIZE_8 |
119 DMA_CFG0_TMODE_SINGLE |
120 DMA_CFG0_TRIGGER_RADIO,
123 DMA_CFG1_PRIORITY_HIGH);
124 ao_dma_start(ao_radio_dma);
126 __critical while (!ao_radio_dma_done)
127 ao_sleep(&ao_radio_dma_done);
128 dma_done = ao_radio_dma_done;
129 ao_mutex_put(&ao_radio_mutex);
131 if (dma_done & AO_DMA_DONE) {
132 printf ("rssi %d status %x\n", rx_packet.rssi, rx_packet.status); flush();
133 if (!(rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK)) {
134 printf ("bad crc\n"); flush();
135 // return AO_DMA_ABORTED;
137 if (rx_packet.packet.len) {
138 if (rx_packet.packet.seq == rx_seq + 1 && rx_used == rx_len)
140 memcpy(rx_data, rx_packet.packet.d, rx_packet.packet.len);
142 rx_len = rx_packet.packet.len;
143 rx_seq = rx_packet.packet.seq;
144 tx_packet.ack = rx_seq;
148 if (rx_packet.packet.ack == tx_packet.seq) {
150 ao_wakeup(&tx_packet);
157 ao_packet_slave(void)
159 tx_packet.addr = ao_serial_number;
160 ao_radio_set_packet();
161 while (ao_packet_enable) {
163 ao_led_toggle(AO_LED_GREEN);
164 ao_delay(AO_MS_TO_TICKS(100));
166 ao_led_toggle(AO_LED_RED);
171 /* Thread for the master side of the packet link */
174 ao_packet_master(void)
177 tx_packet.addr = ao_serial_number;
178 ao_radio_set_packet();
179 while (ao_packet_enable) {
180 ao_delay(AO_MS_TO_TICKS(100));
182 ao_led_toggle(AO_LED_RED);
183 ao_packet_timer_set(AO_MS_TO_TICKS(1000));
184 status = ao_packet_recv();
185 ao_packet_timer_cancel();
186 if (status & AO_DMA_DONE) {
187 ao_led_toggle(AO_LED_GREEN);
188 ao_packet_master_sleeping = 1;
189 ao_sleep(AO_MS_TO_TICKS(1000));
190 ao_packet_master_sleeping = 0;
197 ao_packet_flush(void)
202 /* Wait for previous packet to be received
204 while (tx_packet.len)
205 ao_sleep(&tx_packet);
207 /* Prepare next packet
210 memcpy(&tx_packet.d, tx_data, tx_used);
211 tx_packet.len = tx_used;
215 if (ao_packet_master_sleeping)
216 ao_wake_task(&ao_packet_task);
221 ao_packet_putchar(char c)
223 while (tx_used == AO_PACKET_MAX && ao_packet_enable)
226 if (ao_packet_enable)
227 tx_data[tx_used++] = c;
231 ao_packet_getchar(void) __critical
233 while (rx_used == rx_len && ao_packet_enable)
236 if (!ao_packet_enable)
239 return rx_data[rx_used++];
243 ao_packet_echo(void) __reentrant
246 while (ao_packet_enable) {
247 c = ao_packet_getchar();
248 if (ao_packet_enable)
254 static __xdata struct ao_task ao_packet_echo_task;
257 ao_packet_forward(void) __reentrant
260 ao_packet_enable = 1;
263 ao_radio_set_packet();
264 if (ao_cmd_lex_c == 'm') {
265 while ((c = getchar()) != '~')
270 ao_led_toggle(AO_LED_GREEN);
271 if (rx_packet.packet.d[0] == (uint8_t) '@')
275 ao_packet_enable = 0;
278 if (ao_cmd_lex_c == 'm') {
279 ao_add_task(&ao_packet_timer_task, ao_packet_timer, "timeout");
280 ao_add_task(&ao_packet_task, ao_packet_master, "master");
283 ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
284 ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
285 while ((c = getchar()) != '~') {
286 ao_packet_putchar(c);
290 ao_packet_enable = 0;
291 ao_radio_abort(AO_DMA_ABORTED);
292 while (ao_packet_echo_task.wchan || ao_packet_task.wchan) {
293 ao_wake_task(&ao_packet_echo_task);
294 ao_wake_task(&ao_packet_task);
299 __code struct ao_cmds ao_packet_cmds[] = {
300 { 'p', ao_packet_forward, "p {m|s} Remote packet link. m=master, s=slave" },
301 { 0, ao_packet_forward, NULL },
307 ao_cmd_register(&ao_packet_cmds[0]);