IEEE 802.15.4 subsystem
Sign in or create your account | Project List | Help
IEEE 802.15.4 subsystem Git Source Tree
Root/
Source at commit 125cc6ad9f85735ce97630a40391b5880e1851c2 created 11 years 1 month ago. By Werner Almesberger, tools/lib/atusb-common.c (atusb_rx): fix confusing typo in comment | |
---|---|
1 | /* |
2 | * lib/atusb-common.c - ATUSB access functions shared by all ATUSB drivers |
3 | * |
4 | * Written 2010-2011, 2013 by Werner Almesberger |
5 | * Copyright 2010-2011, 2013 Werner Almesberger |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | */ |
12 | |
13 | |
14 | #include <stdint.h> |
15 | #include <stdlib.h> |
16 | #include <stdio.h> |
17 | #include <string.h> |
18 | #include <usb.h> |
19 | #include <errno.h> |
20 | |
21 | #include "atusb/ep0.h" |
22 | #include "atusb/usb-ids.h" |
23 | |
24 | #include "at86rf230.h" |
25 | #include "usbopen.h" |
26 | #include "driver.h" |
27 | #include "atusb-common.h" |
28 | |
29 | |
30 | /* ----- error handling ---------------------------------------------------- */ |
31 | |
32 | |
33 | int atusb_error(void *handle) |
34 | { |
35 | struct atusb_dsc *dsc = handle; |
36 | |
37 | return dsc->error; |
38 | } |
39 | |
40 | |
41 | int atusb_clear_error(void *handle) |
42 | { |
43 | struct atusb_dsc *dsc = handle; |
44 | int ret; |
45 | |
46 | ret = dsc->error; |
47 | dsc->error = 0; |
48 | return ret; |
49 | } |
50 | |
51 | |
52 | /* ----- open/close -------------------------------------------------------- */ |
53 | |
54 | |
55 | void *atusb_open(const char *arg) |
56 | { |
57 | usb_dev_handle *dev; |
58 | struct atusb_dsc *dsc; |
59 | int res; |
60 | |
61 | usb_unrestrict(); |
62 | if (arg) |
63 | restrict_usb_path(arg); |
64 | dev = open_usb(USB_VENDOR, USB_PRODUCT); |
65 | if (!dev) { |
66 | if (errno == EPERM) |
67 | fprintf(stderr, "Permission denied. " |
68 | "You may need to become root.\n"); |
69 | else |
70 | fprintf(stderr, ":-(\n"); |
71 | return NULL; |
72 | } |
73 | |
74 | res = usb_claim_interface(dev, 0); |
75 | if (res == -EPERM) { |
76 | fprintf(stderr, |
77 | "Permission denied. You may need to become root.\n"); |
78 | return NULL; |
79 | } |
80 | if (res) { |
81 | fprintf(stderr, "usb_claim_interface: %d\n", res); |
82 | return NULL; |
83 | } |
84 | |
85 | dsc = malloc(sizeof(*dsc)); |
86 | if (!dsc) { |
87 | perror("malloc"); |
88 | exit(1); |
89 | } |
90 | |
91 | dsc->dev = dev; |
92 | dsc->error = 0; |
93 | |
94 | atusb_driver.reg_read(dsc, REG_IRQ_STATUS); |
95 | |
96 | return dsc; |
97 | } |
98 | |
99 | |
100 | void atusb_close(void *handle) |
101 | { |
102 | /* to do */ |
103 | } |
104 | |
105 | |
106 | /* ----- device mode ------------------------------------------------------- */ |
107 | |
108 | |
109 | void atusb_reset(void *handle) |
110 | { |
111 | struct atusb_dsc *dsc = handle; |
112 | int res; |
113 | |
114 | if (dsc->error) |
115 | return; |
116 | |
117 | res = |
118 | usb_control_msg(dsc->dev, TO_DEV, ATUSB_RESET, 0, 0, NULL, 0, 1000); |
119 | if (res < 0) { |
120 | fprintf(stderr, "ATUSB_RESET: %d\n", res); |
121 | dsc->error = 1; |
122 | } |
123 | } |
124 | |
125 | |
126 | void atusb_reset_rf(void *handle) |
127 | { |
128 | struct atusb_dsc *dsc = handle; |
129 | int res; |
130 | |
131 | if (dsc->error) |
132 | return; |
133 | |
134 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_RF_RESET, 0, 0, NULL, |
135 | 0, 1000); |
136 | if (res < 0) { |
137 | fprintf(stderr, "ATUSB_RF_RESET: %d\n", res); |
138 | dsc->error = 1; |
139 | } |
140 | } |
141 | |
142 | |
143 | void atusb_test_mode(void *handle) |
144 | { |
145 | struct atusb_dsc *dsc = handle; |
146 | int res; |
147 | |
148 | if (dsc->error) |
149 | return; |
150 | |
151 | res = |
152 | usb_control_msg(dsc->dev, TO_DEV, ATUSB_TEST, 0, 0, NULL, 0, 1000); |
153 | if (res < 0) { |
154 | fprintf(stderr, "ATUSB_TEST: %d\n", res); |
155 | dsc->error = 1; |
156 | } |
157 | } |
158 | |
159 | |
160 | /* ----- SLP_TR ------------------------------------------------------------ */ |
161 | |
162 | |
163 | void atusb_slp_tr(void *handle, int on, int pulse) |
164 | { |
165 | struct atusb_dsc *dsc = handle; |
166 | int res; |
167 | |
168 | if (dsc->error) |
169 | return; |
170 | |
171 | if (!on || !pulse) { |
172 | fprintf(stderr, |
173 | "SLP_TR mode on=%d pulse=%d not supported\n", on, pulse); |
174 | return; |
175 | } |
176 | |
177 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_SLP_TR, 0, 0, NULL, 0, |
178 | 1000); |
179 | if (res < 0) { |
180 | fprintf(stderr, "ATUSB_SLP_TR: %d\n", res); |
181 | dsc->error = 1; |
182 | } |
183 | } |
184 | |
185 | |
186 | /* ----- RF interrupt ------------------------------------------------------ */ |
187 | |
188 | |
189 | /* |
190 | * The logic here is a bit tricky. Assuming that we can get a lot of |
191 | * interrupts, system state can change as follows: |
192 | * |
193 | * Event IRQ_STATUS EP1 on atusb EP1 on host irq |
194 | * INT (var) |
195 | * -------------------- ------- --- ------------ ----------- ----- |
196 | * interrupt A A H EP_IDLE - - |
197 | * INT0 handler - - EP_TX (A) - - |
198 | * interrupt B B H EP_TX (A) - - |
199 | * INT0 handler B H EP_TX (A) - - |
200 | * IN from host B H EP_IDLE A - |
201 | * interrupt C B+C H EP_IDLE A - |
202 | * call to atusb_interrupt_wait |
203 | * read IRQ_STATUS - - EP_IDLE A B+C |
204 | * interrupt D D H EP_IDLE A B+C |
205 | * INT0 handler - - EP_TX (D) A B+C |
206 | * IN from host - - EP_IDLE A, D B+C |
207 | * usb_bulk_read - - EP_IDLE - A+B+C+D |
208 | * usb_bulk_read -> no more data, done |
209 | * |
210 | * We therefore have to consider interrupts queued up at the host and pending |
211 | * in REG_IRQ_STATUS in addition to anything that may arrive while we wait. |
212 | */ |
213 | |
214 | |
215 | int atusb_interrupt_wait(void *handle, int timeout_ms) |
216 | { |
217 | struct atusb_dsc *dsc = handle; |
218 | char buf; |
219 | int res; |
220 | |
221 | if (dsc->error) |
222 | return 0; |
223 | |
224 | res = usb_bulk_read(dsc->dev, 1, |
225 | (char *) &buf, sizeof(buf), timeout_ms); |
226 | if (res == -ETIMEDOUT) |
227 | return 0; |
228 | if (res < 0) { |
229 | fprintf(stderr, "usb_bulk_read: %d\n", res); |
230 | dsc->error = 1; |
231 | return 0; /* handle this via atrf_error */ |
232 | } |
233 | |
234 | return atusb_driver.reg_read(handle, REG_IRQ_STATUS); |
235 | } |
236 | |
237 | |
238 | /* ----- CLKM handling ----------------------------------------------------- */ |
239 | |
240 | |
241 | /* |
242 | * ATmega32U2-based boards don't allow disabling CLKM, so we keep it at 8 MHz. |
243 | * We could accommodate a choice between 8 MHz and 16 MHz, but that's for |
244 | * later. |
245 | */ |
246 | |
247 | int atusb_set_clkm(void *handle, int mhz) |
248 | { |
249 | struct atusb_dsc *dsc = handle; |
250 | uint8_t ids[3]; |
251 | int res; |
252 | |
253 | if (dsc->error) |
254 | return 0; |
255 | res = usb_control_msg(dsc->dev, FROM_DEV, ATUSB_ID, 0, 0, |
256 | (void *) ids, 3, 1000); |
257 | if (res < 0) { |
258 | fprintf(stderr, "ATUSB_ID: %s\n", usb_strerror()); |
259 | dsc->error = 1; |
260 | return 0; |
261 | } |
262 | switch (ids[2]) { |
263 | case HW_TYPE_100813: |
264 | case HW_TYPE_101216: |
265 | break; |
266 | case HW_TYPE_110131: |
267 | if (mhz == 0 || mhz == 8) |
268 | return 1; |
269 | fprintf(stderr, "this board only supports CLKM = 8 MHz\n"); |
270 | return 0; |
271 | default: |
272 | fprintf(stderr, |
273 | "atusb_set_clkm: unknown hardware type 0x%02x\n", ids[2]); |
274 | return 0; |
275 | } |
276 | return atrf_set_clkm_generic(atusb_driver.reg_write, dsc, mhz); |
277 | } |
278 | |
279 | |
280 | /* ----- HardMAC ----------------------------------------------------------- */ |
281 | |
282 | |
283 | void atusb_rx_mode(void *handle, int on) |
284 | { |
285 | struct atusb_dsc *dsc = handle; |
286 | int res; |
287 | |
288 | if (dsc->error) |
289 | return; |
290 | |
291 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_RX_MODE, |
292 | on, 0, NULL, 0, 1000); |
293 | if (res < 0) { |
294 | fprintf(stderr, "ATUSB_RX_MODE: %d\n", res); |
295 | dsc->error = 1; |
296 | } |
297 | } |
298 | |
299 | |
300 | int atusb_rx(void *handle, void *buf, int size, uint8_t *lqi) |
301 | { |
302 | struct atusb_dsc *dsc = handle; |
303 | uint8_t len; |
304 | int res; |
305 | uint8_t tmp[MAX_PSDU+2]; /* PHR, LQI */ |
306 | |
307 | /* |
308 | * Seems that either the USB stack or libusb doesn't like it if we do a |
309 | * read of size one followed by the full read. Therefore, we just do |
310 | * a maximum-sized read and hope that we don't split packets. |
311 | */ |
312 | res = usb_bulk_read(dsc->dev, 1, (char *) tmp, sizeof(tmp), 0); |
313 | if (res < 0) { |
314 | fprintf(stderr, "usb_bulk_read: %d\n", res); |
315 | dsc->error = 1; |
316 | return 0; |
317 | } |
318 | |
319 | len = tmp[0]; |
320 | if (len & 0x80) { |
321 | fprintf(stderr, "atusb_rx: invalid length 0x%02x\n", len); |
322 | return 0; |
323 | } |
324 | if (len > size) { |
325 | fprintf(stderr, "atusb_rx: len %u > size %d\n", len, size); |
326 | return 0; |
327 | } |
328 | if (len > res+2) { |
329 | fprintf(stderr, "atusb_rx: len %u > res %d+2\n", len, res); |
330 | return 0; |
331 | } |
332 | |
333 | memcpy(buf, tmp+1, len); |
334 | if (lqi) |
335 | *lqi = tmp[len+1]; |
336 | |
337 | return len; |
338 | } |
339 | |
340 | |
341 | void atusb_tx(void *handle, const void *buf, int size) |
342 | { |
343 | struct atusb_dsc *dsc = handle; |
344 | uint8_t tmp; |
345 | int res; |
346 | |
347 | if (dsc->error) |
348 | return; |
349 | |
350 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_TX, |
351 | 0, 0, (void *) buf, size, 1000); |
352 | if (res < 0) { |
353 | fprintf(stderr, "ATUSB_TX: %d\n", res); |
354 | dsc->error = 1; |
355 | } |
356 | res = usb_bulk_read(dsc->dev, 1, (char *) &tmp, 1, 0); |
357 | if (res < 0) { |
358 | fprintf(stderr, "usb_bulk_read: %d\n", res); |
359 | dsc->error = 1; |
360 | return; |
361 | } |
362 | if (tmp) |
363 | fprintf(stderr, "atusb_tx: ACK is non-zero 0x%02x\n", tmp); |
364 | } |
365 | |
366 | |
367 | /* ----- Driver-specific hacks --------------------------------------------- */ |
368 | |
369 | |
370 | void *atusb_dev_handle(void *handle) |
371 | { |
372 | struct atusb_dsc *dsc = handle; |
373 | |
374 | return dsc->dev; |
375 | } |
376 |