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