Initial packet bits. Just testing transmission
[fw/altos] / src / ao_packet.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
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.
7  *
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.
12  *
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.
16  */
17
18 #include "ao.h"
19
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;
26
27 static __xdata uint16_t ao_packet_timer_delay;
28 static __xdata uint8_t ao_packet_timer_cancelled;
29
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;
34
35 void
36 ao_packet_timer(void) __reentrant
37 {
38         uint16_t        delay;
39
40         while (ao_packet_enable) {
41
42                 /* wait until the timer task is needed
43                  */
44                 while (!ao_packet_timer_delay && ao_packet_enable)
45                         ao_sleep(&ao_packet_timer_delay);
46
47                 delay = ao_packet_timer_delay;
48                 ao_packet_timer_delay = 0;
49
50                 /* pause waiting for either a timeout or
51                  * a timer cancel
52                  */
53                 ao_delay(delay);
54
55                 /* if not canceled, abort the receive
56                  */
57                 if (!ao_packet_timer_cancelled) {
58                         printf ("packet timeout\n"); flush();
59                         ao_radio_abort(AO_DMA_TIMEOUT);
60                 }
61         }
62         ao_exit();
63 }
64
65 void
66 ao_packet_timer_set(uint16_t delay)
67 {
68         ao_packet_timer_delay = delay;
69         ao_packet_timer_cancelled = 0;
70         ao_wakeup(&ao_packet_timer_delay);
71 }
72
73 void
74 ao_packet_timer_cancel(void)
75 {
76         ao_packet_timer_cancelled = 1;
77         ao_packet_timer_delay = 0;
78         ao_wake_task(&ao_packet_timer_task);
79 }
80
81 void
82 ao_packet_send(void)
83 {
84         ao_config_get();
85         ao_mutex_get(&ao_radio_mutex);
86         ao_radio_idle();
87         RF_CHANNR = ao_config.radio_channel;
88         ao_dma_set_transfer(ao_radio_dma,
89                             &tx_packet,
90                             &RFDXADDR,
91                             sizeof (struct ao_packet),
92                             DMA_CFG0_WORDSIZE_8 |
93                             DMA_CFG0_TMODE_SINGLE |
94                             DMA_CFG0_TRIGGER_RADIO,
95                             DMA_CFG1_SRCINC_1 |
96                             DMA_CFG1_DESTINC_0 |
97                             DMA_CFG1_PRIORITY_HIGH);
98         ao_dma_start(ao_radio_dma);
99         RFST = RFST_STX;
100         __critical while (!ao_radio_dma_done)
101                 ao_sleep(&ao_radio_dma_done);
102         ao_mutex_put(&ao_radio_mutex);
103 }
104
105 uint8_t
106 ao_packet_recv(void)
107 {
108         uint8_t dma_done;
109
110         ao_config_get();
111         ao_mutex_get(&ao_radio_mutex);
112         ao_radio_idle();
113         RF_CHANNR = ao_config.radio_channel;
114         ao_dma_set_transfer(ao_radio_dma,
115                             &RFDXADDR,
116                             &rx_packet,
117                             sizeof (struct ao_packet_recv),
118                             DMA_CFG0_WORDSIZE_8 |
119                             DMA_CFG0_TMODE_SINGLE |
120                             DMA_CFG0_TRIGGER_RADIO,
121                             DMA_CFG1_SRCINC_0 |
122                             DMA_CFG1_DESTINC_1 |
123                             DMA_CFG1_PRIORITY_HIGH);
124         ao_dma_start(ao_radio_dma);
125         RFST = RFST_SRX;
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);
130
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;
136                 }
137                 if (rx_packet.packet.len) {
138                         if (rx_packet.packet.seq == rx_seq + 1 && rx_used == rx_len)
139                         {
140                                 memcpy(rx_data, rx_packet.packet.d, rx_packet.packet.len);
141                                 rx_used = 0;
142                                 rx_len = rx_packet.packet.len;
143                                 rx_seq = rx_packet.packet.seq;
144                                 tx_packet.ack = rx_seq;
145                                 ao_wakeup(&rx_data);
146                         }
147                 }
148                 if (rx_packet.packet.ack == tx_packet.seq) {
149                         tx_packet.len = 0;
150                         ao_wakeup(&tx_packet);
151                 }
152         }
153         return dma_done;
154 }
155
156 void
157 ao_packet_slave(void)
158 {
159         tx_packet.addr = ao_serial_number;
160         ao_radio_set_packet();
161         while (ao_packet_enable) {
162                 ao_packet_recv();
163                 ao_led_toggle(AO_LED_GREEN);
164                 ao_delay(AO_MS_TO_TICKS(100));
165                 ao_packet_send();
166                 ao_led_toggle(AO_LED_RED);
167         }
168         ao_exit();
169 }
170
171 /* Thread for the master side of the packet link */
172
173 void
174 ao_packet_master(void)
175 {
176         uint8_t status;
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));
181                 ao_packet_send();
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;
191                 }
192         }
193         ao_exit();
194 }
195
196 void
197 ao_packet_flush(void)
198 {
199         if (!tx_used)
200                 return;
201
202         /* Wait for previous packet to be received
203          */
204         while (tx_packet.len)
205                 ao_sleep(&tx_packet);
206
207         /* Prepare next packet
208          */
209         if (tx_used) {
210                 memcpy(&tx_packet.d, tx_data, tx_used);
211                 tx_packet.len = tx_used;
212                 tx_packet.seq++;
213                 tx_used = 0;
214
215                 if (ao_packet_master_sleeping)
216                         ao_wake_task(&ao_packet_task);
217         }
218 }
219
220 void
221 ao_packet_putchar(char c)
222 {
223         while (tx_used == AO_PACKET_MAX && ao_packet_enable)
224                 ao_packet_flush();
225
226         if (ao_packet_enable)
227                 tx_data[tx_used++] = c;
228 }
229
230 char
231 ao_packet_getchar(void) __critical
232 {
233         while (rx_used == rx_len && ao_packet_enable)
234                 ao_sleep(&rx_data);
235
236         if (!ao_packet_enable)
237                 return 0;
238
239         return rx_data[rx_used++];
240 }
241
242 static void
243 ao_packet_echo(void) __reentrant
244 {
245         uint8_t c;
246         while (ao_packet_enable) {
247                 c = ao_packet_getchar();
248                 if (ao_packet_enable)
249                         putchar(c);
250         }
251         ao_exit();
252 }
253
254 static __xdata struct ao_task   ao_packet_echo_task;
255
256 static void
257 ao_packet_forward(void) __reentrant
258 {
259         char c;
260         ao_packet_enable = 1;
261         ao_cmd_white();
262
263         ao_radio_set_packet();
264         if (ao_cmd_lex_c == 'm') {
265                 while ((c = getchar()) != '~')
266                         ao_packet_send();
267         } else {
268                 for (;;) {
269                         ao_packet_recv();
270                         ao_led_toggle(AO_LED_GREEN);
271                         if (rx_packet.packet.d[0] == (uint8_t) '@')
272                                 break;
273                 }
274         }
275         ao_packet_enable = 0;
276         return;
277 #if 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");
281         }
282         else
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);
287                 if (c == '\n')
288                         ao_packet_flush();
289         }
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);
295         }
296 #endif
297 }
298
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 },
302 };
303
304 void
305 ao_packet_init(void)
306 {
307         ao_cmd_register(&ao_packet_cmds[0]);
308 }