Root/tools/lib/atusb-common.c

Source at commit 4690466a53e14209b1fdd8acf58761142a691af8 created 6 years 2 months ago.
By Werner Almesberger, tools/lib/atusb-common.c (atusb_interrupt_wait): fix embarrassing build failure
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
32int atusb_error(void *handle)
33{
34    struct atusb_dsc *dsc = handle;
35
36    return dsc->error;
37}
38
39
40int 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
54void *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
99void atusb_close(void *handle)
100{
101    /* to do */
102}
103
104
105/* ----- device mode ------------------------------------------------------- */
106
107
108void 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
125void 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
142void 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
162void 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
214int 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
246int 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
282void 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
299int 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
342void 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
371void *atusb_dev_handle(void *handle)
372{
373    struct atusb_dsc *dsc = handle;
374
375    return dsc->dev;
376}
377

Archive Download this file



interactive