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 struct ao_task ao_packet_task;
28 static __xdata uint8_t ao_packet_enable;
29 static __xdata uint8_t ao_packet_master_sleeping;
34 ao_led_on(AO_LED_RED);
36 ao_mutex_get(&ao_radio_mutex);
37 if (tx_used && tx_packet.len == 0) {
38 memcpy(&tx_packet.d, tx_data, tx_used);
39 tx_packet.len = tx_used;
46 RF_CHANNR = ao_config.radio_channel;
47 ao_dma_set_transfer(ao_radio_dma,
50 sizeof (struct ao_packet),
52 DMA_CFG0_TMODE_SINGLE |
53 DMA_CFG0_TRIGGER_RADIO,
56 DMA_CFG1_PRIORITY_HIGH);
57 ao_dma_start(ao_radio_dma);
59 __critical while (!ao_radio_done)
60 ao_sleep(&ao_radio_done);
61 ao_mutex_put(&ao_radio_mutex);
62 ao_led_off(AO_LED_RED);
70 ao_led_on(AO_LED_GREEN);
72 ao_mutex_get(&ao_radio_mutex);
74 RF_CHANNR = ao_config.radio_channel;
75 ao_dma_set_transfer(ao_radio_dma,
78 sizeof (struct ao_packet_recv),
80 DMA_CFG0_TMODE_SINGLE |
81 DMA_CFG0_TRIGGER_RADIO,
84 DMA_CFG1_PRIORITY_HIGH);
85 ao_dma_start(ao_radio_dma);
87 __critical while (!ao_radio_dma_done)
88 if (ao_sleep(&ao_radio_dma_done) != 0)
90 dma_done = ao_radio_dma_done;
91 ao_mutex_put(&ao_radio_mutex);
92 ao_led_off(AO_LED_GREEN);
94 if (dma_done & AO_DMA_DONE) {
95 if (!(rx_packet.status & PKT_APPEND_STATUS_1_CRC_OK))
96 return AO_DMA_ABORTED;
97 if (rx_packet.packet.len == AO_PACKET_SYN) {
98 rx_seq = rx_packet.packet.seq;
99 tx_packet.seq = rx_packet.packet.ack;
100 tx_packet.ack = rx_seq;
101 } else if (rx_packet.packet.len) {
102 if (rx_packet.packet.seq == (uint8_t) (rx_seq + (uint8_t) 1) && rx_used == rx_len) {
104 printf ("rx len %3d seq %3d ack %3d\n",
105 rx_packet.packet.len,
106 rx_packet.packet.seq,
107 rx_packet.packet.ack);
110 memcpy(rx_data, rx_packet.packet.d, rx_packet.packet.len);
112 rx_len = rx_packet.packet.len;
113 rx_seq = rx_packet.packet.seq;
114 tx_packet.ack = rx_seq;
118 if (rx_packet.packet.ack == tx_packet.seq) {
120 ao_wakeup(&tx_packet);
127 ao_packet_slave(void)
129 ao_radio_set_packet();
130 tx_packet.addr = ao_serial_number;
131 tx_packet.len = AO_PACKET_SYN;
132 while (ao_packet_enable) {
139 /* Thread for the master side of the packet link */
142 ao_packet_master(void)
146 ao_radio_set_packet();
147 tx_packet.addr = ao_serial_number;
148 tx_packet.len = AO_PACKET_SYN;
149 while (ao_packet_enable) {
151 ao_alarm(AO_MS_TO_TICKS(100));
152 status = ao_packet_recv();
153 if (status & AO_DMA_DONE) {
154 /* if we can transmit data, do so */
155 if (tx_used && tx_packet.len == 0)
157 ao_packet_master_sleeping = 1;
158 ao_delay(AO_MS_TO_TICKS(1000));
159 ao_packet_master_sleeping = 0;
166 ao_packet_flush(void)
168 /* If there is data to send, and this is the master,
169 * then poke the master to send all queued data
171 if (tx_used && ao_packet_master_sleeping)
172 ao_wake_task(&ao_packet_task);
176 ao_packet_putchar(char c)
178 while (tx_used == AO_PACKET_MAX && ao_packet_enable) {
183 if (ao_packet_enable)
184 tx_data[tx_used++] = c;
188 ao_packet_getchar(void) __critical
190 while (rx_used == rx_len && ao_packet_enable) {
191 /* poke the master to get more data */
192 if (ao_packet_master_sleeping)
193 ao_wake_task(&ao_packet_task);
197 if (!ao_packet_enable)
200 return rx_data[rx_used++];
204 ao_packet_echo(void) __reentrant
207 while (ao_packet_enable) {
208 c = ao_packet_getchar();
209 if (ao_packet_enable) {
211 if (c == (uint8_t) '\n' || c == (uint8_t) '\r')
218 static __xdata struct ao_task ao_packet_echo_task;
221 ao_packet_forward(void) __reentrant
224 ao_packet_enable = 1;
227 if (ao_cmd_lex_c == 'm')
228 ao_add_task(&ao_packet_task, ao_packet_master, "master");
230 ao_add_task(&ao_packet_task, ao_packet_slave, "slave");
231 ao_add_task(&ao_packet_echo_task, ao_packet_echo, "echo");
232 while ((c = getchar()) != '~')
233 ao_packet_putchar(c);
234 ao_packet_enable = 0;
236 while (ao_packet_echo_task.wchan || ao_packet_task.wchan) {
237 ao_wake_task(&ao_packet_echo_task);
238 ao_wake_task(&ao_packet_task);
242 __code struct ao_cmds ao_packet_cmds[] = {
243 { 'p', ao_packet_forward, "p {m|s} Remote packet link. m=master, s=slave" },
244 { 0, ao_packet_forward, NULL },
250 ao_cmd_register(&ao_packet_cmds[0]);