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 10b6d88af91815681e16f8e44a803a6b35fffbdf created 12 years 9 months ago. By Werner Almesberger, libatrf: simplify use of atrf_interrupt_wait now this it is mandatory | |
---|---|
1 | /* |
2 | * lib/atusb-common.c - ATUSB access functions shared by all ATUSB drivers |
3 | * |
4 | * Written 2010-2011 by Werner Almesberger |
5 | * Copyright 2010-2011 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 <usb.h> |
18 | #include <errno.h> |
19 | |
20 | #include "atusb/ep0.h" |
21 | #include "atusb/usb-ids.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(USB_VENDOR, USB_PRODUCT); |
64 | if (!dev) { |
65 | fprintf(stderr, ":-(\n"); |
66 | return NULL; |
67 | } |
68 | |
69 | res = usb_claim_interface(dev, 0); |
70 | if (res) { |
71 | fprintf(stderr, "usb_claim_interface: %d\n", res); |
72 | return NULL; |
73 | } |
74 | |
75 | dsc = malloc(sizeof(*dsc)); |
76 | if (!dsc) { |
77 | perror("malloc"); |
78 | exit(1); |
79 | } |
80 | |
81 | dsc->dev = dev; |
82 | dsc->error = 0; |
83 | |
84 | return dsc; |
85 | } |
86 | |
87 | |
88 | void atusb_close(void *handle) |
89 | { |
90 | /* to do */ |
91 | } |
92 | |
93 | |
94 | /* ----- device mode ------------------------------------------------------- */ |
95 | |
96 | |
97 | void atusb_reset(void *handle) |
98 | { |
99 | struct atusb_dsc *dsc = handle; |
100 | int res; |
101 | |
102 | if (dsc->error) |
103 | return; |
104 | |
105 | res = |
106 | usb_control_msg(dsc->dev, TO_DEV, ATUSB_RESET, 0, 0, NULL, 0, 1000); |
107 | if (res < 0) { |
108 | fprintf(stderr, "ATUSB_RESET: %d\n", res); |
109 | dsc->error = 1; |
110 | } |
111 | } |
112 | |
113 | |
114 | void atusb_reset_rf(void *handle) |
115 | { |
116 | struct atusb_dsc *dsc = handle; |
117 | int res; |
118 | |
119 | if (dsc->error) |
120 | return; |
121 | |
122 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_RF_RESET, 0, 0, NULL, |
123 | 0, 1000); |
124 | if (res < 0) { |
125 | fprintf(stderr, "ATUSB_RF_RESET: %d\n", res); |
126 | dsc->error = 1; |
127 | } |
128 | } |
129 | |
130 | |
131 | void atusb_test_mode(void *handle) |
132 | { |
133 | struct atusb_dsc *dsc = handle; |
134 | int res; |
135 | |
136 | if (dsc->error) |
137 | return; |
138 | |
139 | res = |
140 | usb_control_msg(dsc->dev, TO_DEV, ATUSB_TEST, 0, 0, NULL, 0, 1000); |
141 | if (res < 0) { |
142 | fprintf(stderr, "ATUSB_TEST: %d\n", res); |
143 | dsc->error = 1; |
144 | } |
145 | } |
146 | |
147 | |
148 | /* ----- SLP_TR ------------------------------------------------------------ */ |
149 | |
150 | |
151 | void atusb_slp_tr(void *handle, int on, int pulse) |
152 | { |
153 | struct atusb_dsc *dsc = handle; |
154 | int res; |
155 | |
156 | if (dsc->error) |
157 | return; |
158 | |
159 | if (!on || !pulse) { |
160 | fprintf(stderr, |
161 | "SLP_TR mode on=%d pulse=%d not supported\n", on, pulse); |
162 | return; |
163 | } |
164 | |
165 | res = usb_control_msg(dsc->dev, TO_DEV, ATUSB_SLP_TR, 0, 0, NULL, 0, |
166 | 1000); |
167 | if (res < 0) { |
168 | fprintf(stderr, "ATUSB_SLP_TR: %d\n", res); |
169 | dsc->error = 1; |
170 | } |
171 | } |
172 | |
173 | |
174 | /* ----- RF interrupt ------------------------------------------------------ */ |
175 | |
176 | |
177 | /* |
178 | * The logic here is a bit tricky. Assuming that we can get a lot of |
179 | * interrupts, system state can change as follows: |
180 | * |
181 | * Event IRQ_STATUS EP1 on atusb EP1 on host irq |
182 | * INT (var) |
183 | * -------------------- ------- --- ------------ ----------- ----- |
184 | * interrupt A A H EP_IDLE - - |
185 | * INT0 handler - - EP_TX (A) - - |
186 | * interrupt B B H EP_TX (A) - - |
187 | * INT0 handler B H EP_TX (A) - - |
188 | * IN from host B H EP_IDLE A - |
189 | * interrupt C B+C H EP_IDLE A - |
190 | * call to atusb_interrupt_wait |
191 | * read IRQ_STATUS - - EP_IDLE A B+C |
192 | * interrupt D D H EP_IDLE A B+C |
193 | * INT0 handler - - EP_TX (D) A B+C |
194 | * IN from host - - EP_IDLE A, D B+C |
195 | * usb_bulk_read - - EP_IDLE - A+B+C+D |
196 | * usb_bulk_read -> no more data, done |
197 | * |
198 | * We therefore have to consider interrupts queued up at the host and pending |
199 | * in REG_IRQ_STATUS in addition to anything that may arrive while we wait. |
200 | */ |
201 | |
202 | |
203 | int atusb_interrupt_wait(void *handle, int timeout_ms) |
204 | { |
205 | struct atusb_dsc *dsc = handle; |
206 | uint8_t irq, buf[100]; |
207 | int res, i; |
208 | |
209 | if (dsc->error) |
210 | return 0; |
211 | |
212 | irq = atusb_driver.reg_read(handle, REG_IRQ_STATUS); |
213 | if (irq) |
214 | timeout_ms = 1; |
215 | |
216 | while (1) { |
217 | res = usb_bulk_read(dsc->dev, 1, |
218 | (char *) &buf, sizeof(buf), timeout_ms); |
219 | if (res == -ETIMEDOUT) |
220 | break; |
221 | if (res < 0) { |
222 | fprintf(stderr, "usb_bulk_read: %d\n", res); |
223 | dsc->error = 1; |
224 | return 0; /* handle this via atrf_error */ |
225 | } |
226 | timeout_ms = 1; |
227 | for (i = 0; i != res; i++) |
228 | irq |= buf[i]; |
229 | } |
230 | return irq; |
231 | } |
232 | |
233 | |
234 | /* ----- CLKM handling ----------------------------------------------------- */ |
235 | |
236 | |
237 | /* |
238 | * ATmega32U2-based boards don't allow disabling CLKM, so we keep it at 8 MHz. |
239 | * We could accommodate a choice between 8 MHz and 16 MHz, but that's for |
240 | * later. |
241 | */ |
242 | |
243 | int atusb_set_clkm(void *handle, int mhz) |
244 | { |
245 | struct atusb_dsc *dsc = handle; |
246 | uint8_t ids[3]; |
247 | int res; |
248 | |
249 | if (dsc->error) |
250 | return 0; |
251 | res = usb_control_msg(dsc->dev, FROM_DEV, ATUSB_ID, 0, 0, |
252 | (void *) ids, 3, 1000); |
253 | if (res < 0) { |
254 | fprintf(stderr, "ATUSB_ID: %s\n", usb_strerror()); |
255 | dsc->error = 1; |
256 | return 0; |
257 | } |
258 | switch (ids[2]) { |
259 | case HW_TYPE_100813: |
260 | case HW_TYPE_101216: |
261 | break; |
262 | case HW_TYPE_110131: |
263 | if (mhz == 0 || mhz == 8) |
264 | return 1; |
265 | fprintf(stderr, "this board only supports CLKM = 8 MHz\n"); |
266 | return 0; |
267 | default: |
268 | fprintf(stderr, |
269 | "atusb_set_clkm: unknown hardware type 0x%02x\n", ids[2]); |
270 | return 0; |
271 | } |
272 | return atrf_set_clkm_generic(atusb_driver.reg_write, dsc, mhz); |
273 | } |
274 | |
275 | |
276 | /* ----- Driver-specific hacks --------------------------------------------- */ |
277 | |
278 | |
279 | void *atusb_dev_handle(void *handle) |
280 | { |
281 | struct atusb_dsc *dsc = handle; |
282 | |
283 | return dsc->dev; |
284 | } |
285 |