From: realraum Date: Mon, 12 Dec 2011 21:49:11 +0000 (+0000) Subject: atarted new rf433rcv as copy of pjrc rawhid X-Git-Url: https://git.realraum.at/?p=svn42.git;a=commitdiff_plain;h=deb2b278d460a716e0e2d8be370b1ee8f8963e34 atarted new rf433rcv as copy of pjrc rawhid --- diff --git a/rf433rcv/pc/Makefile b/rf433rcv/pc/Makefile new file mode 100644 index 0000000..62d2d66 --- /dev/null +++ b/rf433rcv/pc/Makefile @@ -0,0 +1,59 @@ + +OS = LINUX +#OS = MACOSX +#OS = WINDOWS + +PROG = rawhid_test + +# To set up Ubuntu Linux to cross compile for Windows: +# +# apt-get install mingw32 mingw32-binutils mingw32-runtime +# +# Just edit the variable above for WINDOWS, then use "make" to build rawhid.exe + +ifeq ($(OS), LINUX) +TARGET = $(PROG) +CC = gcc +STRIP = strip +CFLAGS = -Wall -O2 -DOS_$(OS) +LIBS = -lusb +else ifeq ($(OS), MACOSX) +TARGET = $(PROG).dmg +SDK = /Developer/SDKs/MacOSX10.5.sdk +ARCH = -mmacosx-version-min=10.5 -arch ppc -arch i386 +CC = gcc +STRIP = strip +CFLAGS = -Wall -O2 -DOS_$(OS) -isysroot $(SDK) $(ARCH) +LIBS = $(ARCH) -Wl,-syslibroot,$(SDK) -framework IOKit -framework CoreFoundation +else ifeq ($(OS), WINDOWS) +TARGET = $(PROG).exe +CC = i586-mingw32msvc-gcc +STRIP = i586-mingw32msvc-strip +CFLAGS = -Wall -O2 -DOS_$(OS) +LIBS = -lhid -lsetupapi +endif + +OBJS = $(PROG).o hid.o + + +all: $(TARGET) + +$(PROG): $(OBJS) + $(CC) -o $(PROG) $(OBJS) $(LIBS) + $(STRIP) $(PROG) + +$(PROG).exe: $(PROG) + cp $(PROG) $(PROG).exe + +$(PROG).dmg: $(PROG) + mkdir tmp + cp $(PROG) tmp + hdiutil create -ov -volname "Raw HID Test" -srcfolder tmp $(PROG).dmg + +hid.o: hid_$(OS).c hid.h + $(CC) $(CFLAGS) -c -o $@ $< + +clean: + rm -f *.o $(PROG) $(PROG).exe $(PROG).dmg + rm -rf tmp + diff --git a/rf433rcv/pc/hid.h b/rf433rcv/pc/hid.h new file mode 100644 index 0000000..4d83703 --- /dev/null +++ b/rf433rcv/pc/hid.h @@ -0,0 +1,6 @@ + +int rawhid_open(int max, int vid, int pid, int usage_page, int usage); +int rawhid_recv(int num, void *buf, int len, int timeout); +int rawhid_send(int num, void *buf, int len, int timeout); +void rawhid_close(int num); + diff --git a/rf433rcv/pc/hid_LINUX.c b/rf433rcv/pc/hid_LINUX.c new file mode 100644 index 0000000..8e98113 --- /dev/null +++ b/rf433rcv/pc/hid_LINUX.c @@ -0,0 +1,381 @@ +/* Simple Raw HID functions for Linux - for use with Teensy RawHID example + * http://www.pjrc.com/teensy/rawhid.html + * Copyright (c) 2009 PJRC.COM, LLC + * + * rawhid_open - open 1 or more devices + * rawhid_recv - receive a packet + * rawhid_send - send a packet + * rawhid_close - close a device + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above description, website URL and copyright notice and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Version 1.0: Initial Release + */ + +#include +#include +#include +#include + +#include "hid.h" + + +// On Linux there are several options to access HID devices. +// +// libusb 0.1 - the only way that works well on all distributions +// libusb 1.0 - someday will become standard on most distributions +// hidraw driver - relatively new, not supported on many distributions (yet) +// hiddev driver - old, ubuntu, fedora, others dropping support +// usbfs - low level usb API: http://www.kernel.org/doc/htmldocs/usb.html#usbfs +// +// This code uses libusb 0.1, which is well supported on all linux distributions +// and very stable and widely used by many programs. libusb 0.1 only provides a +// simple synchronous interface, basically the same as this code needs. However, +// if you want non-blocking I/O, libusb 0.1 simply does not provide that. There +// is also no kernel-level buffering, so performance is poor. +// +// UPDATE: As of November 2011, hidraw support seems to be working well in all +// major linux distributions. Embedded and "small" distros, used on ARM boards, +// routers and embedded hardware stil seem to omit the hidraw driver. +// +// The hidraw driver is a great solution. However, it has only been supported +// by relatively recent (in 2009) kernels. Here is a quick survey of the status +// of hidraw support in various distributions as of Sept 2009: +// +// Fedora 11: works, kernel 2.6.29.4 +// Mandiva 2009.1: works, kernel 2.6.29.1 +// Ubuntu 9.10-alpha6: works, kernel 2.6.31 +// Ubuntu 9.04: sysfs attrs chain broken (hidraw root only), 2.6.28 kernel +// openSUSE 11.1: sysfs attrs chain broken (hidraw root only), 2.6.27.7 kernel +// Debian Live, Lenny 5.0.2: sysfs attrs chain broken (hidraw root only), 2.6.26 +// SimplyMEPIS 8.0.10: sysfs attrs chain broken (hidraw root only), 2.6.27 +// Mint 7: sysfs attrs chain broken (hidraw root only), 2.6.28 kernel +// Gentoo 2008.0-r1: sysfs attrs chain broken (hidraw root only), 2.6.24 kernel +// Centos 5: no hidraw or hiddev devices, 2.6.18 kernel +// Slitaz 2.0: no hidraw devices (has hiddev), 2.6.25.5 kernel +// Puppy 4.3: no hidraw devices (has hiddev), 2.6.30.5 kernel +// Damn Small 4.4.10: (would not boot) +// Gentoo 10.0-test20090926: (would not boot) +// PCLinuxOS 2009.2: (would not boot) +// Slackware: (no live cd available? www.slackware-live.org dead) + + + +#define printf(...) // comment this out for lots of info + + +// a list of all opened HID devices, so the caller can +// simply refer to them by number +typedef struct hid_struct hid_t; +static hid_t *first_hid = NULL; +static hid_t *last_hid = NULL; +struct hid_struct { + usb_dev_handle *usb; + int open; + int iface; + int ep_in; + int ep_out; + struct hid_struct *prev; + struct hid_struct *next; +}; + + +// private functions, not intended to be used from outside this file +static void add_hid(hid_t *h); +static hid_t * get_hid(int num); +static void free_all_hid(void); +static void hid_close(hid_t *hid); +static int hid_parse_item(uint32_t *val, uint8_t **data, const uint8_t *end); + + +// rawhid_recv - receive a packet +// Inputs: +// num = device to receive from (zero based) +// buf = buffer to receive packet +// len = buffer's size +// timeout = time to wait, in milliseconds +// Output: +// number of bytes received, or -1 on error +// +int rawhid_recv(int num, void *buf, int len, int timeout) +{ + hid_t *hid; + int r; + + hid = get_hid(num); + if (!hid || !hid->open) return -1; + r = usb_interrupt_read(hid->usb, hid->ep_in, buf, len, timeout); + if (r >= 0) return r; + if (r == -110) return 0; // timeout + return -1; +} + +// rawhid_send - send a packet +// Inputs: +// num = device to transmit to (zero based) +// buf = buffer containing packet to send +// len = number of bytes to transmit +// timeout = time to wait, in milliseconds +// Output: +// number of bytes sent, or -1 on error +// +int rawhid_send(int num, void *buf, int len, int timeout) +{ + hid_t *hid; + + hid = get_hid(num); + if (!hid || !hid->open) return -1; + if (hid->ep_out) { + return usb_interrupt_write(hid->usb, hid->ep_out, buf, len, timeout); + } else { + return usb_control_msg(hid->usb, 0x21, 9, 0, hid->iface, buf, len, timeout); + } +} + +// rawhid_open - open 1 or more devices +// +// Inputs: +// max = maximum number of devices to open +// vid = Vendor ID, or -1 if any +// pid = Product ID, or -1 if any +// usage_page = top level usage page, or -1 if any +// usage = top level usage number, or -1 if any +// Output: +// actual number of devices opened +// +int rawhid_open(int max, int vid, int pid, int usage_page, int usage) +{ + struct usb_bus *bus; + struct usb_device *dev; + struct usb_interface *iface; + struct usb_interface_descriptor *desc; + struct usb_endpoint_descriptor *ep; + usb_dev_handle *u; + uint8_t buf[1024], *p; + int i, n, len, tag, ep_in, ep_out, count=0, claimed; + uint32_t val=0, parsed_usage, parsed_usage_page; + hid_t *hid; + + if (first_hid) free_all_hid(); + printf("rawhid_open, max=%d\n", max); + if (max < 1) return 0; + usb_init(); + usb_find_busses(); + usb_find_devices(); + for (bus = usb_get_busses(); bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if (vid > 0 && dev->descriptor.idVendor != vid) continue; + if (pid > 0 && dev->descriptor.idProduct != pid) continue; + if (!dev->config) continue; + if (dev->config->bNumInterfaces < 1) continue; + printf("device: vid=%04X, pic=%04X, with %d iface\n", + dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->config->bNumInterfaces); + iface = dev->config->interface; + u = NULL; + claimed = 0; + for (i=0; iconfig->bNumInterfaces && iface; i++, iface++) { + desc = iface->altsetting; + if (!desc) continue; + printf(" type %d, %d, %d\n", desc->bInterfaceClass, + desc->bInterfaceSubClass, desc->bInterfaceProtocol); + if (desc->bInterfaceClass != 3) continue; + if (desc->bInterfaceSubClass != 0) continue; + if (desc->bInterfaceProtocol != 0) continue; + ep = desc->endpoint; + ep_in = ep_out = 0; + for (n = 0; n < desc->bNumEndpoints; n++, ep++) { + if (ep->bEndpointAddress & 0x80) { + if (!ep_in) ep_in = ep->bEndpointAddress & 0x7F; + printf(" IN endpoint %d\n", ep_in); + } else { + if (!ep_out) ep_out = ep->bEndpointAddress; + printf(" OUT endpoint %d\n", ep_out); + } + } + if (!ep_in) continue; + if (!u) { + u = usb_open(dev); + if (!u) { + printf(" unable to open device\n"); + break; + } + } + printf(" hid interface (generic)\n"); + if (usb_get_driver_np(u, i, (char *)buf, sizeof(buf)) >= 0) { + printf(" in use by driver \"%s\"\n", buf); + if (usb_detach_kernel_driver_np(u, i) < 0) { + printf(" unable to detach from kernel\n"); + continue; + } + } + if (usb_claim_interface(u, i) < 0) { + printf(" unable claim interface %d\n", i); + continue; + } + len = usb_control_msg(u, 0x81, 6, 0x2200, i, (char *)buf, sizeof(buf), 250); + printf(" descriptor, len=%d\n", len); + if (len < 2) { + usb_release_interface(u, i); + continue; + } + p = buf; + parsed_usage_page = parsed_usage = 0; + while ((tag = hid_parse_item(&val, &p, buf + len)) >= 0) { + printf(" tag: %X, val %X\n", tag, val); + if (tag == 4) parsed_usage_page = val; + if (tag == 8) parsed_usage = val; + if (parsed_usage_page && parsed_usage) break; + } + if ((!parsed_usage_page) || (!parsed_usage) || + (usage_page > 0 && parsed_usage_page != usage_page) || + (usage > 0 && parsed_usage != usage)) { + usb_release_interface(u, i); + continue; + } + hid = (struct hid_struct *)malloc(sizeof(struct hid_struct)); + if (!hid) { + usb_release_interface(u, i); + continue; + } + hid->usb = u; + hid->iface = i; + hid->ep_in = ep_in; + hid->ep_out = ep_out; + hid->open = 1; + add_hid(hid); + claimed++; + count++; + if (count >= max) return count; + } + if (u && !claimed) usb_close(u); + } + } + return count; +} + + +// rawhid_close - close a device +// +// Inputs: +// num = device to close (zero based) +// Output +// (nothing) +// +void rawhid_close(int num) +{ + hid_t *hid; + + hid = get_hid(num); + if (!hid || !hid->open) return; + hid_close(hid); +} + +// Chuck Robey wrote a real HID report parser +// (chuckr@telenix.org) chuckr@chuckr.org +// http://people.freebsd.org/~chuckr/code/python/uhidParser-0.2.tbz +// this tiny thing only needs to extract the top-level usage page +// and usage, and even then is may not be truly correct, but it does +// work with the Teensy Raw HID example. +static int hid_parse_item(uint32_t *val, uint8_t **data, const uint8_t *end) +{ + const uint8_t *p = *data; + uint8_t tag; + int table[4] = {0, 1, 2, 4}; + int len; + + if (p >= end) return -1; + if (p[0] == 0xFE) { + // long item, HID 1.11, 6.2.2.3, page 27 + if (p + 5 >= end || p + p[1] >= end) return -1; + tag = p[2]; + *val = 0; + len = p[1] + 5; + } else { + // short item, HID 1.11, 6.2.2.2, page 26 + tag = p[0] & 0xFC; + len = table[p[0] & 0x03]; + if (p + len + 1 >= end) return -1; + switch (p[0] & 0x03) { + case 3: *val = p[1] | (p[2] << 8) | (p[3] << 16) | (p[4] << 24); break; + case 2: *val = p[1] | (p[2] << 8); break; + case 1: *val = p[1]; break; + case 0: *val = 0; break; + } + } + *data += len + 1; + return tag; +} + + +static void add_hid(hid_t *h) +{ + if (!first_hid || !last_hid) { + first_hid = last_hid = h; + h->next = h->prev = NULL; + return; + } + last_hid->next = h; + h->prev = last_hid; + h->next = NULL; + last_hid = h; +} + + +static hid_t * get_hid(int num) +{ + hid_t *p; + for (p = first_hid; p && num > 0; p = p->next, num--) ; + return p; +} + + +static void free_all_hid(void) +{ + hid_t *p, *q; + + for (p = first_hid; p; p = p->next) { + hid_close(p); + } + p = first_hid; + while (p) { + q = p; + p = p->next; + free(q); + } + first_hid = last_hid = NULL; +} + + +static void hid_close(hid_t *hid) +{ + hid_t *p; + int others=0; + + usb_release_interface(hid->usb, hid->iface); + for (p = first_hid; p; p = p->next) { + if (p->open && p->usb == hid->usb) others++; + } + if (!others) usb_close(hid->usb); + hid->usb = NULL; +} + + + diff --git a/rf433rcv/pc/hid_MACOSX.c b/rf433rcv/pc/hid_MACOSX.c new file mode 100644 index 0000000..c5d5d1b --- /dev/null +++ b/rf433rcv/pc/hid_MACOSX.c @@ -0,0 +1,412 @@ +/* Simple Raw HID functions for Linux - for use with Teensy RawHID example + * http://www.pjrc.com/teensy/rawhid.html + * Copyright (c) 2009 PJRC.COM, LLC + * + * rawhid_open - open 1 or more devices + * rawhid_recv - receive a packet + * rawhid_send - send a packet + * rawhid_close - close a device + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above description, website URL and copyright notice and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Version 1.0: Initial Release + */ + +#include +#include +#include +#include +#include +#include + +#include "hid.h" + +#define BUFFER_SIZE 64 + +#define printf(...) // comment this out to get lots of info printed + + +// a list of all opened HID devices, so the caller can +// simply refer to them by number +typedef struct hid_struct hid_t; +typedef struct buffer_struct buffer_t; +static hid_t *first_hid = NULL; +static hid_t *last_hid = NULL; +struct hid_struct { + IOHIDDeviceRef ref; + int open; + uint8_t buffer[BUFFER_SIZE]; + buffer_t *first_buffer; + buffer_t *last_buffer; + struct hid_struct *prev; + struct hid_struct *next; +}; +struct buffer_struct { + struct buffer_struct *next; + uint32_t len; + uint8_t buf[BUFFER_SIZE]; +}; + +// private functions, not intended to be used from outside this file +static void add_hid(hid_t *); +static hid_t * get_hid(int); +static void free_all_hid(void); +static void hid_close(hid_t *); +static void attach_callback(void *, IOReturn, void *, IOHIDDeviceRef); +static void detach_callback(void *, IOReturn, void *hid_mgr, IOHIDDeviceRef dev); +static void timeout_callback(CFRunLoopTimerRef, void *); +static void input_callback(void *, IOReturn, void *, IOHIDReportType, + uint32_t, uint8_t *, CFIndex); + + + +// rawhid_recv - receive a packet +// Inputs: +// num = device to receive from (zero based) +// buf = buffer to receive packet +// len = buffer's size +// timeout = time to wait, in milliseconds +// Output: +// number of bytes received, or -1 on error +// +int rawhid_recv(int num, void *buf, int len, int timeout) +{ + hid_t *hid; + buffer_t *b; + CFRunLoopTimerRef timer=NULL; + CFRunLoopTimerContext context; + int ret=0, timeout_occurred=0; + + if (len < 1) return 0; + hid = get_hid(num); + if (!hid || !hid->open) return -1; + if ((b = hid->first_buffer) != NULL) { + if (len > b->len) len = b->len; + memcpy(buf, b->buf, len); + hid->first_buffer = b->next; + free(b); + return len; + } + memset(&context, 0, sizeof(context)); + context.info = &timeout_occurred; + timer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + + (double)timeout / 1000.0, 0, 0, 0, timeout_callback, &context); + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode); + while (1) { + CFRunLoopRun(); + if ((b = hid->first_buffer) != NULL) { + if (len > b->len) len = b->len; + memcpy(buf, b->buf, len); + hid->first_buffer = b->next; + free(b); + ret = len; + break; + } + if (!hid->open) { + printf("rawhid_recv, device not open\n"); + ret = -1; + break; + } + if (timeout_occurred) break; + } + CFRunLoopTimerInvalidate(timer); + CFRelease(timer); + return ret; +} + +static void input_callback(void *context, IOReturn ret, void *sender, + IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len) +{ + buffer_t *n; + hid_t *hid; + + printf("input_callback\n"); + if (ret != kIOReturnSuccess || len < 1) return; + hid = context; + if (!hid || hid->ref != sender) return; + n = (buffer_t *)malloc(sizeof(buffer_t)); + if (!n) return; + if (len > BUFFER_SIZE) len = BUFFER_SIZE; + memcpy(n->buf, data, len); + n->len = len; + n->next = NULL; + if (!hid->first_buffer || !hid->last_buffer) { + hid->first_buffer = hid->last_buffer = n; + } else { + hid->last_buffer->next = n; + hid->last_buffer = n; + } + CFRunLoopStop(CFRunLoopGetCurrent()); +} + +static void timeout_callback(CFRunLoopTimerRef timer, void *info) +{ + printf("timeout_callback\n"); + *(int *)info = 1; + CFRunLoopStop(CFRunLoopGetCurrent()); +} + + +void output_callback(void *context, IOReturn ret, void *sender, + IOHIDReportType type, uint32_t id, uint8_t *data, CFIndex len) +{ + printf("output_callback, r=%d\n", ret); + if (ret == kIOReturnSuccess) { + *(int *)context = len; + } else { + // timeout if not success? + *(int *)context = 0; + } + CFRunLoopStop(CFRunLoopGetCurrent()); +} + + +// rawhid_send - send a packet +// Inputs: +// num = device to transmit to (zero based) +// buf = buffer containing packet to send +// len = number of bytes to transmit +// timeout = time to wait, in milliseconds +// Output: +// number of bytes sent, or -1 on error +// +int rawhid_send(int num, void *buf, int len, int timeout) +{ + hid_t *hid; + int result=-100; + + hid = get_hid(num); + if (!hid || !hid->open) return -1; +#if 1 + #warning "Send timeout not implemented on MACOSX" + IOReturn ret = IOHIDDeviceSetReport(hid->ref, kIOHIDReportTypeOutput, 0, buf, len); + result = (ret == kIOReturnSuccess) ? len : -1; +#endif +#if 0 + // No matter what I tried this never actually sends an output + // report and output_callback never gets called. Why?? + // Did I miss something? This is exactly the same params as + // the sync call that works. Is it an Apple bug? + // (submitted to Apple on 22-sep-2009, problem ID 7245050) + // + IOHIDDeviceScheduleWithRunLoop(hid->ref, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + // should already be scheduled with run loop by attach_callback, + // sadly this doesn't make any difference either way + + // could this be related? + // http://lists.apple.com/archives/usb/2008/Aug/msg00021.html + // + IOHIDDeviceSetReportWithCallback(hid->ref, kIOHIDReportTypeOutput, + 0, buf, len, (double)timeout / 1000.0, output_callback, &result); + while (1) { + printf("enter run loop (send)\n"); + CFRunLoopRun(); + printf("leave run loop (send)\n"); + if (result > -100) break; + if (!hid->open) { + result = -1; + break; + } + } +#endif + return result; +} + + +// rawhid_open - open 1 or more devices +// +// Inputs: +// max = maximum number of devices to open +// vid = Vendor ID, or -1 if any +// pid = Product ID, or -1 if any +// usage_page = top level usage page, or -1 if any +// usage = top level usage number, or -1 if any +// Output: +// actual number of devices opened +// +int rawhid_open(int max, int vid, int pid, int usage_page, int usage) +{ + static IOHIDManagerRef hid_manager=NULL; + CFMutableDictionaryRef dict; + CFNumberRef num; + IOReturn ret; + hid_t *p; + int count=0; + + if (first_hid) free_all_hid(); + printf("rawhid_open, max=%d\n", max); + if (max < 1) return 0; + // Start the HID Manager + // http://developer.apple.com/technotes/tn2007/tn2187.html + if (!hid_manager) { + hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (hid_manager == NULL || CFGetTypeID(hid_manager) != IOHIDManagerGetTypeID()) { + if (hid_manager) CFRelease(hid_manager); + return 0; + } + } + if (vid > 0 || pid > 0 || usage_page > 0 || usage > 0) { + // Tell the HID Manager what type of devices we want + dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!dict) return 0; + if (vid > 0) { + num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vid); + CFDictionarySetValue(dict, CFSTR(kIOHIDVendorIDKey), num); + CFRelease(num); + } + if (pid > 0) { + num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid); + CFDictionarySetValue(dict, CFSTR(kIOHIDProductIDKey), num); + CFRelease(num); + } + if (usage_page > 0) { + num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage_page); + CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsagePageKey), num); + CFRelease(num); + } + if (usage > 0) { + num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + CFDictionarySetValue(dict, CFSTR(kIOHIDPrimaryUsageKey), num); + CFRelease(num); + } + IOHIDManagerSetDeviceMatching(hid_manager, dict); + CFRelease(dict); + } else { + IOHIDManagerSetDeviceMatching(hid_manager, NULL); + } + // set up a callbacks for device attach & detach + IOHIDManagerScheduleWithRunLoop(hid_manager, CFRunLoopGetCurrent(), + kCFRunLoopDefaultMode); + IOHIDManagerRegisterDeviceMatchingCallback(hid_manager, attach_callback, NULL); + IOHIDManagerRegisterDeviceRemovalCallback(hid_manager, detach_callback, NULL); + ret = IOHIDManagerOpen(hid_manager, kIOHIDOptionsTypeNone); + if (ret != kIOReturnSuccess) { + IOHIDManagerUnscheduleFromRunLoop(hid_manager, + CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + CFRelease(hid_manager); + return 0; + } + printf("run loop\n"); + // let it do the callback for all devices + while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == kCFRunLoopRunHandledSource) ; + // count up how many were added by the callback + for (p = first_hid; p; p = p->next) count++; + return count; +} + + +// rawhid_close - close a device +// +// Inputs: +// num = device to close (zero based) +// Output +// (nothing) +// +void rawhid_close(int num) +{ + hid_t *hid; + + hid = get_hid(num); + if (!hid || !hid->open) return; + hid_close(hid); + hid->open = 0; +} + + +static void add_hid(hid_t *h) +{ + if (!first_hid || !last_hid) { + first_hid = last_hid = h; + h->next = h->prev = NULL; + return; + } + last_hid->next = h; + h->prev = last_hid; + h->next = NULL; + last_hid = h; +} + + +static hid_t * get_hid(int num) +{ + hid_t *p; + for (p = first_hid; p && num > 0; p = p->next, num--) ; + return p; +} + + +static void free_all_hid(void) +{ + hid_t *p, *q; + + for (p = first_hid; p; p = p->next) { + hid_close(p); + } + p = first_hid; + while (p) { + q = p; + p = p->next; + free(q); + } + first_hid = last_hid = NULL; +} + + +static void hid_close(hid_t *hid) +{ + if (!hid || !hid->open || !hid->ref) return; + IOHIDDeviceUnscheduleFromRunLoop(hid->ref, CFRunLoopGetCurrent( ), kCFRunLoopDefaultMode); + IOHIDDeviceClose(hid->ref, kIOHIDOptionsTypeNone); + hid->ref = NULL; +} + +static void detach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) +{ + hid_t *p; + + printf("detach callback\n"); + for (p = first_hid; p; p = p->next) { + if (p->ref == dev) { + p->open = 0; + CFRunLoopStop(CFRunLoopGetCurrent()); + return; + } + } +} + + +static void attach_callback(void *context, IOReturn r, void *hid_mgr, IOHIDDeviceRef dev) +{ + struct hid_struct *h; + + printf("attach callback\n"); + if (IOHIDDeviceOpen(dev, kIOHIDOptionsTypeNone) != kIOReturnSuccess) return; + h = (hid_t *)malloc(sizeof(hid_t)); + if (!h) return; + memset(h, 0, sizeof(hid_t)); + IOHIDDeviceScheduleWithRunLoop(dev, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + IOHIDDeviceRegisterInputReportCallback(dev, h->buffer, sizeof(h->buffer), + input_callback, h); + h->ref = dev; + h->open = 1; + add_hid(h); +} + + diff --git a/rf433rcv/pc/hid_WINDOWS.c b/rf433rcv/pc/hid_WINDOWS.c new file mode 100644 index 0000000..0718773 --- /dev/null +++ b/rf433rcv/pc/hid_WINDOWS.c @@ -0,0 +1,328 @@ +/* Simple Raw HID functions for Windows - for use with Teensy RawHID example + * http://www.pjrc.com/teensy/rawhid.html + * Copyright (c) 2009 PJRC.COM, LLC + * + * rawhid_open - open 1 or more devices + * rawhid_recv - receive a packet + * rawhid_send - send a packet + * rawhid_close - close a device + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above description, website URL and copyright notice and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Version 1.0: Initial Release + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hid.h" + + +// a list of all opened HID devices, so the caller can +// simply refer to them by number +typedef struct hid_struct hid_t; +static hid_t *first_hid = NULL; +static hid_t *last_hid = NULL; +struct hid_struct { + HANDLE handle; + int open; + struct hid_struct *prev; + struct hid_struct *next; +}; +static HANDLE rx_event=NULL; +static HANDLE tx_event=NULL; +static CRITICAL_SECTION rx_mutex; +static CRITICAL_SECTION tx_mutex; + + +// private functions, not intended to be used from outside this file +static void add_hid(hid_t *h); +static hid_t * get_hid(int num); +static void free_all_hid(void); +static void hid_close(hid_t *hid); +void print_win32_err(void); + + + + +// rawhid_recv - receive a packet +// Inputs: +// num = device to receive from (zero based) +// buf = buffer to receive packet +// len = buffer's size +// timeout = time to wait, in milliseconds +// Output: +// number of bytes received, or -1 on error +// +int rawhid_recv(int num, void *buf, int len, int timeout) +{ + hid_t *hid; + unsigned char tmpbuf[516]; + OVERLAPPED ov; + DWORD n, r; + + if (sizeof(tmpbuf) < len + 1) return -1; + hid = get_hid(num); + if (!hid || !hid->open) return -1; + EnterCriticalSection(&rx_mutex); + ResetEvent(&rx_event); + memset(&ov, 0, sizeof(ov)); + ov.hEvent = rx_event; + if (!ReadFile(hid->handle, tmpbuf, len + 1, NULL, &ov)) { + if (GetLastError() != ERROR_IO_PENDING) goto return_error; + r = WaitForSingleObject(rx_event, timeout); + if (r == WAIT_TIMEOUT) goto return_timeout; + if (r != WAIT_OBJECT_0) goto return_error; + } + if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) goto return_error; + LeaveCriticalSection(&rx_mutex); + if (n <= 0) return -1; + n--; + if (n > len) n = len; + memcpy(buf, tmpbuf + 1, n); + return n; +return_timeout: + CancelIo(hid->handle); + LeaveCriticalSection(&rx_mutex); + return 0; +return_error: + print_win32_err(); + LeaveCriticalSection(&rx_mutex); + return -1; +} + +// rawhid_send - send a packet +// Inputs: +// num = device to transmit to (zero based) +// buf = buffer containing packet to send +// len = number of bytes to transmit +// timeout = time to wait, in milliseconds +// Output: +// number of bytes sent, or -1 on error +// +int rawhid_send(int num, void *buf, int len, int timeout) +{ + hid_t *hid; + unsigned char tmpbuf[516]; + OVERLAPPED ov; + DWORD n, r; + + if (sizeof(tmpbuf) < len + 1) return -1; + hid = get_hid(num); + if (!hid || !hid->open) return -1; + EnterCriticalSection(&tx_mutex); + ResetEvent(&tx_event); + memset(&ov, 0, sizeof(ov)); + ov.hEvent = tx_event; + tmpbuf[0] = 0; + memcpy(tmpbuf + 1, buf, len); + if (!WriteFile(hid->handle, tmpbuf, len + 1, NULL, &ov)) { + if (GetLastError() != ERROR_IO_PENDING) goto return_error; + r = WaitForSingleObject(tx_event, timeout); + if (r == WAIT_TIMEOUT) goto return_timeout; + if (r != WAIT_OBJECT_0) goto return_error; + } + if (!GetOverlappedResult(hid->handle, &ov, &n, FALSE)) goto return_error; + LeaveCriticalSection(&tx_mutex); + if (n <= 0) return -1; + return n - 1; +return_timeout: + CancelIo(hid->handle); + LeaveCriticalSection(&tx_mutex); + return 0; +return_error: + print_win32_err(); + LeaveCriticalSection(&tx_mutex); + return -1; +} + +// rawhid_open - open 1 or more devices +// +// Inputs: +// max = maximum number of devices to open +// vid = Vendor ID, or -1 if any +// pid = Product ID, or -1 if any +// usage_page = top level usage page, or -1 if any +// usage = top level usage number, or -1 if any +// Output: +// actual number of devices opened +// +int rawhid_open(int max, int vid, int pid, int usage_page, int usage) +{ + GUID guid; + HDEVINFO info; + DWORD index=0, reqd_size; + SP_DEVICE_INTERFACE_DATA iface; + SP_DEVICE_INTERFACE_DETAIL_DATA *details; + HIDD_ATTRIBUTES attrib; + PHIDP_PREPARSED_DATA hid_data; + HIDP_CAPS capabilities; + HANDLE h; + BOOL ret; + hid_t *hid; + int count=0; + + if (first_hid) free_all_hid(); + if (max < 1) return 0; + if (!rx_event) { + rx_event = CreateEvent(NULL, TRUE, TRUE, NULL); + tx_event = CreateEvent(NULL, TRUE, TRUE, NULL); + InitializeCriticalSection(&rx_mutex); + InitializeCriticalSection(&tx_mutex); + } + HidD_GetHidGuid(&guid); + info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if (info == INVALID_HANDLE_VALUE) return 0; + for (index=0; 1 ;index++) { + iface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + ret = SetupDiEnumDeviceInterfaces(info, NULL, &guid, index, &iface); + if (!ret) return count; + SetupDiGetInterfaceDeviceDetail(info, &iface, NULL, 0, &reqd_size, NULL); + details = (SP_DEVICE_INTERFACE_DETAIL_DATA *)malloc(reqd_size); + if (details == NULL) continue; + + memset(details, 0, reqd_size); + details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + ret = SetupDiGetDeviceInterfaceDetail(info, &iface, details, + reqd_size, NULL, NULL); + if (!ret) { + free(details); + continue; + } + h = CreateFile(details->DevicePath, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + free(details); + if (h == INVALID_HANDLE_VALUE) continue; + attrib.Size = sizeof(HIDD_ATTRIBUTES); + ret = HidD_GetAttributes(h, &attrib); + //printf("vid: %4x\n", attrib.VendorID); + if (!ret || (vid > 0 && attrib.VendorID != vid) || + (pid > 0 && attrib.ProductID != pid) || + !HidD_GetPreparsedData(h, &hid_data)) { + CloseHandle(h); + continue; + } + if (!HidP_GetCaps(hid_data, &capabilities) || + (usage_page > 0 && capabilities.UsagePage != usage_page) || + (usage > 0 && capabilities.Usage != usage)) { + HidD_FreePreparsedData(hid_data); + CloseHandle(h); + continue; + } + HidD_FreePreparsedData(hid_data); + hid = (struct hid_struct *)malloc(sizeof(struct hid_struct)); + if (!hid) { + CloseHandle(h); + continue; + } + hid->handle = h; + hid->open = 1; + add_hid(hid); + count++; + if (count >= max) return count; + } + return count; +} + + +// rawhid_close - close a device +// +// Inputs: +// num = device to close (zero based) +// Output +// (nothing) +// +void rawhid_close(int num) +{ + hid_t *hid; + + hid = get_hid(num); + if (!hid || !hid->open) return; + hid_close(hid); +} + + + +static void add_hid(hid_t *h) +{ + if (!first_hid || !last_hid) { + first_hid = last_hid = h; + h->next = h->prev = NULL; + return; + } + last_hid->next = h; + h->prev = last_hid; + h->next = NULL; + last_hid = h; +} + + +static hid_t * get_hid(int num) +{ + hid_t *p; + for (p = first_hid; p && num > 0; p = p->next, num--) ; + return p; +} + + +static void free_all_hid(void) +{ + hid_t *p, *q; + + for (p = first_hid; p; p = p->next) { + hid_close(p); + } + p = first_hid; + while (p) { + q = p; + p = p->next; + free(q); + } + first_hid = last_hid = NULL; +} + + +static void hid_close(hid_t *hid) +{ + CloseHandle(hid->handle); + hid->handle = NULL; +} + + +void print_win32_err(void) +{ + char buf[256]; + DWORD err; + + err = GetLastError(); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, + 0, buf, sizeof(buf), NULL); + printf("err %ld: %s\n", err, buf); +} + + + + + diff --git a/rf433rcv/pc/rawhid_test.c b/rf433rcv/pc/rawhid_test.c new file mode 100644 index 0000000..7bea892 --- /dev/null +++ b/rf433rcv/pc/rawhid_test.c @@ -0,0 +1,100 @@ +#include +#include +#include + +#if defined(OS_LINUX) || defined(OS_MACOSX) +#include +#include +#elif defined(OS_WINDOWS) +#include +#endif + +#include "hid.h" + + +static char get_keystroke(void); + + +int main() +{ + int i, r, num; + char c, buf[64]; + + // C-based example is 16C0:0480:FFAB:0200 + r = rawhid_open(1, 0x16C0, 0x0480, 0xFFAB, 0x0200); + if (r <= 0) { + // Arduino-based example is 16C0:0486:FFAB:0200 + r = rawhid_open(1, 0x16C0, 0x0486, 0xFFAB, 0x0200); + if (r <= 0) { + printf("no rawhid device found\n"); + return -1; + } + } + printf("found rawhid device\n"); + + while (1) { + // check if any Raw HID packet has arrived + num = rawhid_recv(0, buf, 64, 220); + if (num < 0) { + printf("\nerror reading, device went offline\n"); + rawhid_close(0); + return 0; + } + if (num > 0) { + printf("\nrecv %d bytes:\n", num); + for (i=0; i= 32) { + printf("\ngot key '%c', sending...\n", c); + buf[0] = c; + for (i=1; i<64; i++) { + buf[i] = 0; + } + rawhid_send(0, buf, 64, 100); + } + } +} + +#if defined(OS_LINUX) || defined(OS_MACOSX) +// Linux (POSIX) implementation of _kbhit(). +// Morgan McGuire, morgan@cs.brown.edu +static int _kbhit() { + static const int STDIN = 0; + static int initialized = 0; + int bytesWaiting; + + if (!initialized) { + // Use termios to turn off line buffering + struct termios term; + tcgetattr(STDIN, &term); + term.c_lflag &= ~ICANON; + tcsetattr(STDIN, TCSANOW, &term); + setbuf(stdin, NULL); + initialized = 1; + } + ioctl(STDIN, FIONREAD, &bytesWaiting); + return bytesWaiting; +} +static char _getch(void) { + char c; + if (fread(&c, 1, 1, stdin) < 1) return 0; + return c; +} +#endif + + +static char get_keystroke(void) +{ + if (_kbhit()) { + char c = _getch(); + if (c >= 32) return c; + } + return 0; +} + + diff --git a/rf433rcv/teensy/Makefile b/rf433rcv/teensy/Makefile new file mode 100644 index 0000000..edf9f8a --- /dev/null +++ b/rf433rcv/teensy/Makefile @@ -0,0 +1,615 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al. +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# Carlos Lamas +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# Target file name (without extension). +TARGET = example + + +# List C source files here. (C dependencies are automatically generated.) +SRC = $(TARGET).c \ + usb_rawhid.c \ + analog.c + + +# MCU name, you MUST set this to match the board you are using +# type "make clean" after changing this, so all files will be rebuilt +# +#MCU = at90usb162 # Teensy 1.0 +MCU = atmega32u4 # Teensy 2.0 +#MCU = at90usb646 # Teensy++ 1.0 +#MCU = at90usb1286 # Teensy++ 2.0 + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +F_CPU = 16000000 + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = + + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu99 + + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL + + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) + + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + + + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -ffunction-sections +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +#CFLAGS += -mshort-calls +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wundef +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) + + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CPPFLAGS += -Wundef +#CPPFLAGS += -mshort-calls +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += -Wl,--relax +LDFLAGS += -Wl,--gc-sections +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -T linker_script.x + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = stk500v2 + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = com1 # programmer connected to serial device + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + + + + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex eep lss sym +#build: lib + + +elf: $(TARGET).elf +hex: $(TARGET).hex +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf +ELFSIZE = $(SIZE) $(TARGET).elf + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT = $(OBJCOPY) --debugging +COFFCONVERT += --change-section-address .data-0x800000 +COFFCONVERT += --change-section-address .bss-0x800000 +COFFCONVERT += --change-section-address .noinit-0x800000 +COFFCONVERT += --change-section-address .eeprom-0x810000 + + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S -z $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff \ +clean clean_list program debug gdb-config diff --git a/rf433rcv/teensy/analog.c b/rf433rcv/teensy/analog.c new file mode 100644 index 0000000..99bf3b6 --- /dev/null +++ b/rf433rcv/teensy/analog.c @@ -0,0 +1,57 @@ +// Simple analog to digitial conversion, similar to Wiring/Arduino + +#include +#include + +#include "analog.h" + + +#if defined(__AVR_ATmega32U4__) + +uint8_t analog_reference_config_val = 0x40; + +static const uint8_t PROGMEM adc_mapping[] = { + 0, 1, 4, 5, 6, 7, 13, 12, 11, 10, 9, 8 +}; + +int analogRead(uint8_t pin) +{ + uint8_t low, adc; + + if (pin >= 12) return 0; + adc = pgm_read_byte(adc_mapping + pin); + if (adc < 8) { + DIDR0 |= (1 << adc); + ADCSRB = 0; + ADMUX = analog_reference_config_val | adc; + } else { + adc -= 8; + DIDR2 |= (1 << adc); + ADCSRB = (1<= 8) return 0; + DIDR0 |= (1 << pin); + ADMUX = analog_reference_config_val | pin; + ADCSRA = (1< + +#if defined(__AVR_AT90USB162__) +#define analogRead(pin) (0) +#define analogReference(ref) +#else +int16_t analogRead(uint8_t pin); +extern uint8_t analog_reference_config_val; +#define analogReference(ref) (analog_reference_config_val = (ref) << 6) +#endif + +#endif diff --git a/rf433rcv/teensy/example.c b/rf433rcv/teensy/example.c new file mode 100644 index 0000000..635b16f --- /dev/null +++ b/rf433rcv/teensy/example.c @@ -0,0 +1,109 @@ +/* Teensy RawHID example + * http://www.pjrc.com/teensy/rawhid.html + * Copyright (c) 2009 PJRC.COM, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above description, website URL and copyright notice and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include +#include "usb_rawhid.h" +#include "analog.h" + +#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) + +volatile uint8_t do_output=0; +uint8_t buffer[64]; + +int main(void) +{ + int8_t r; + uint8_t i; + uint16_t val, count=0; + + // set for 16 MHz clock + CPU_PRESCALE(0); + + // Initialize the USB, and then wait for the host to set configuration. + // If the Teensy is powered without a PC connected to the USB port, + // this will wait forever. + usb_init(); + while (!usb_configured()) /* wait */ ; + + // Wait an extra second for the PC's operating system to load drivers + // and do whatever it does to actually be ready for input + _delay_ms(1000); + + // Configure timer 0 to generate a timer overflow interrupt every + // 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock + TCCR0A = 0x00; + TCCR0B = 0x05; + TIMSK0 = (1< 0) { + // output 4 bits to D0, D1, D2, D3 pins + DDRD = 0x0F; + PORTD = (PORTD & 0xF0) | (buffer[0] & 0x0F); + // ignore the other 63.5 bytes.... + } + // if time to send output, transmit something interesting + if (do_output) { + do_output = 0; + // send a packet, first 2 bytes 0xABCD + buffer[0] = 0xAB; + buffer[1] = 0xCD; + // put A/D measurements into next 24 bytes + for (i=0; i<12; i++) { + val = analogRead(i); + buffer[i * 2 + 2] = val >> 8; + buffer[i * 2 + 3] = val & 255; + } + // most of the packet filled with zero + for (i=26; i<62; i++) { + buffer[i] = 0; + } + // put a count in the last 2 bytes + buffer[62] = count >> 8; + buffer[63] = count & 255; + // send the packet + usb_rawhid_send(buffer, 50); + count++; + } + } +} + +// This interrupt routine is run approx 61 times per second. +ISR(TIMER0_OVF_vect) +{ + static uint8_t count=0; + + // set the do_output variable every 2 seconds + if (++count > 122) { + count = 0; + do_output = 1; + } +} + + + diff --git a/rf433rcv/teensy/usb_rawhid.c b/rf433rcv/teensy/usb_rawhid.c new file mode 100644 index 0000000..dae1214 --- /dev/null +++ b/rf433rcv/teensy/usb_rawhid.c @@ -0,0 +1,940 @@ +/* Teensy RawHID example + * http://www.pjrc.com/teensy/rawhid.html + * Copyright (c) 2009 PJRC.COM, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above description, website URL and copyright notice and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// Version 1.0: Initial Release +// Version 1.1: fixed bug in analog + +#define USB_PRIVATE_INCLUDE +#include "usb_rawhid.h" + +/************************************************************************** + * + * Configurable Options + * + **************************************************************************/ + +// You can change these to give your code its own name. +#define STR_MANUFACTURER L"MfgName" +#define STR_PRODUCT L"Teensy Raw HID Example" + +// These 4 numbers identify your device. Set these to +// something that is (hopefully) not used by any others! +#define VENDOR_ID 0x16C0 +#define PRODUCT_ID 0x0480 +#define RAWHID_USAGE_PAGE 0xFFAB // recommended: 0xFF00 to 0xFFFF +#define RAWHID_USAGE 0x0200 // recommended: 0x0100 to 0xFFFF + +// These determine the bandwidth that will be allocated +// for your communication. You do not need to use it +// all, but allocating more than necessary means reserved +// bandwidth is no longer available to other USB devices. +#define RAWHID_TX_SIZE 64 // transmit packet size +#define RAWHID_TX_INTERVAL 2 // max # of ms between transmit packets +#define RAWHID_RX_SIZE 64 // receive packet size +#define RAWHID_RX_INTERVAL 8 // max # of ms between receive packets + + +/************************************************************************** + * + * Endpoint Buffer Configuration + * + **************************************************************************/ + +#define ENDPOINT0_SIZE 32 +#define RAWHID_INTERFACE 0 +#define RAWHID_TX_ENDPOINT 1 +#define RAWHID_RX_ENDPOINT 2 + +#if defined(__AVR_AT90USB162__) +#define RAWHID_TX_BUFFER EP_SINGLE_BUFFER +#define RAWHID_RX_BUFFER EP_SINGLE_BUFFER +#else +#define RAWHID_TX_BUFFER EP_DOUBLE_BUFFER +#define RAWHID_RX_BUFFER EP_DOUBLE_BUFFER +#endif + +static const uint8_t PROGMEM endpoint_config_table[] = { + 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(RAWHID_TX_SIZE) | RAWHID_TX_BUFFER, + 1, EP_TYPE_INTERRUPT_OUT, EP_SIZE(RAWHID_RX_SIZE) | RAWHID_RX_BUFFER, + 0, + 0 +}; + + +/************************************************************************** + * + * Descriptor Data + * + **************************************************************************/ + +// Descriptors are the data that your computer reads when it auto-detects +// this USB device (called "enumeration" in USB lingo). The most commonly +// changed items are editable at the top of this file. Changing things +// in here should only be done by those who've read chapter 9 of the USB +// spec and relevant portions of any USB class specifications! + + +static uint8_t PROGMEM device_descriptor[] = { + 18, // bLength + 1, // bDescriptorType + 0x00, 0x02, // bcdUSB + 0, // bDeviceClass + 0, // bDeviceSubClass + 0, // bDeviceProtocol + ENDPOINT0_SIZE, // bMaxPacketSize0 + LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor + LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice + 1, // iManufacturer + 2, // iProduct + 0, // iSerialNumber + 1 // bNumConfigurations +}; + +static uint8_t PROGMEM rawhid_hid_report_desc[] = { + 0x06, LSB(RAWHID_USAGE_PAGE), MSB(RAWHID_USAGE_PAGE), + 0x0A, LSB(RAWHID_USAGE), MSB(RAWHID_USAGE), + 0xA1, 0x01, // Collection 0x01 + 0x75, 0x08, // report size = 8 bits + 0x15, 0x00, // logical minimum = 0 + 0x26, 0xFF, 0x00, // logical maximum = 255 + 0x95, RAWHID_TX_SIZE, // report count + 0x09, 0x01, // usage + 0x81, 0x02, // Input (array) + 0x95, RAWHID_RX_SIZE, // report count + 0x09, 0x02, // usage + 0x91, 0x02, // Output (array) + 0xC0 // end collection +}; + + +#define CONFIG1_DESC_SIZE (9+9+9+7+7) +#define RAWHID_HID_DESC_OFFSET (9+9) +static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { + // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 + 9, // bLength; + 2, // bDescriptorType; + LSB(CONFIG1_DESC_SIZE), // wTotalLength + MSB(CONFIG1_DESC_SIZE), + 1, // bNumInterfaces + 1, // bConfigurationValue + 0, // iConfiguration + 0xC0, // bmAttributes + 50, // bMaxPower + + // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 + 9, // bLength + 4, // bDescriptorType + RAWHID_INTERFACE, // bInterfaceNumber + 0, // bAlternateSetting + 2, // bNumEndpoints + 0x03, // bInterfaceClass (0x03 = HID) + 0x00, // bInterfaceSubClass (0x01 = Boot) + 0x00, // bInterfaceProtocol (0x01 = Keyboard) + 0, // iInterface + // HID interface descriptor, HID 1.11 spec, section 6.2.1 + 9, // bLength + 0x21, // bDescriptorType + 0x11, 0x01, // bcdHID + 0, // bCountryCode + 1, // bNumDescriptors + 0x22, // bDescriptorType + sizeof(rawhid_hid_report_desc), // wDescriptorLength + 0, + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + RAWHID_TX_ENDPOINT | 0x80, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + RAWHID_TX_SIZE, 0, // wMaxPacketSize + RAWHID_TX_INTERVAL, // bInterval + // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 + 7, // bLength + 5, // bDescriptorType + RAWHID_RX_ENDPOINT, // bEndpointAddress + 0x03, // bmAttributes (0x03=intr) + RAWHID_RX_SIZE, 0, // wMaxPacketSize + RAWHID_RX_INTERVAL // bInterval +}; + +// If you're desperate for a little extra code memory, these strings +// can be completely removed if iManufacturer, iProduct, iSerialNumber +// in the device desciptor are changed to zeros. +struct usb_string_descriptor_struct { + uint8_t bLength; + uint8_t bDescriptorType; + int16_t wString[]; +}; +static struct usb_string_descriptor_struct PROGMEM string0 = { + 4, + 3, + {0x0409} +}; +static struct usb_string_descriptor_struct PROGMEM string1 = { + sizeof(STR_MANUFACTURER), + 3, + STR_MANUFACTURER +}; +static struct usb_string_descriptor_struct PROGMEM string2 = { + sizeof(STR_PRODUCT), + 3, + STR_PRODUCT +}; + +// This table defines which descriptor data is sent for each specific +// request from the host (in wValue and wIndex). +static struct descriptor_list_struct { + uint16_t wValue; + uint16_t wIndex; + const uint8_t *addr; + uint8_t length; +} PROGMEM descriptor_list[] = { + {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, + {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, + {0x2200, RAWHID_INTERFACE, rawhid_hid_report_desc, sizeof(rawhid_hid_report_desc)}, + {0x2100, RAWHID_INTERFACE, config1_descriptor+RAWHID_HID_DESC_OFFSET, 9}, + {0x0300, 0x0000, (const uint8_t *)&string0, 4}, + {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, + {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)} +}; +#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) + + +/************************************************************************** + * + * Variables - these are the only non-stack RAM usage + * + **************************************************************************/ + +// zero when we are not configured, non-zero when enumerated +static volatile uint8_t usb_configuration=0; + +// these are a more reliable timeout than polling the +// frame counter (UDFNUML) +static volatile uint8_t rx_timeout_count=0; +static volatile uint8_t tx_timeout_count=0; + + + +/************************************************************************** + * + * Public Functions - these are the API intended for the user + * + **************************************************************************/ + + +// initialize USB +void usb_init(void) +{ + HW_CONFIG(); + USB_FREEZE(); // enable USB + PLL_CONFIG(); // config PLL + while (!(PLLCSR & (1<= 64) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 63) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 62) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 61) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 60) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 59) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 58) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 57) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 56) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 55) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 54) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 53) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 52) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 51) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 50) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 49) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 48) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 47) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 46) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 45) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 44) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 43) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 42) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 41) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 40) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 39) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 38) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 37) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 36) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 35) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 34) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 33) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 32) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 31) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 30) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 29) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 28) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 27) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 26) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 25) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 24) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 23) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 22) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 21) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 20) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 19) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 18) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 17) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 16) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 15) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 14) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 13) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 12) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 11) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 10) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 9) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 8) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 7) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 6) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 5) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 4) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 3) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 2) + *buffer++ = UEDATX; + #endif + #if (RAWHID_RX_SIZE >= 1) + *buffer++ = UEDATX; + #endif + // release the buffer + UEINTX = 0x6B; + SREG = intr_state; + return RAWHID_RX_SIZE; +} + +// send a packet, with timeout +int8_t usb_rawhid_send(const uint8_t *buffer, uint8_t timeout) +{ + uint8_t intr_state; + + // if we're not online (enumerated and configured), error + if (!usb_configuration) return -1; + intr_state = SREG; + cli(); + tx_timeout_count = timeout; + UENUM = RAWHID_TX_ENDPOINT; + // wait for the FIFO to be ready to accept data + while (1) { + if (UEINTX & (1<= 64) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 63) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 62) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 61) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 60) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 59) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 58) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 57) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 56) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 55) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 54) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 53) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 52) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 51) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 50) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 49) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 48) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 47) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 46) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 45) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 44) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 43) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 42) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 41) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 40) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 39) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 38) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 37) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 36) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 35) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 34) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 33) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 32) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 31) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 30) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 29) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 28) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 27) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 26) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 25) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 24) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 23) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 22) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 21) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 20) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 19) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 18) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 17) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 16) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 15) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 14) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 13) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 12) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 11) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 10) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 9) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 8) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 7) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 6) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 5) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 4) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 3) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 2) + UEDATX = *buffer++; + #endif + #if (RAWHID_TX_SIZE >= 1) + UEDATX = *buffer++; + #endif + // transmit it now + UEINTX = 0x3A; + SREG = intr_state; + return RAWHID_TX_SIZE; +} + + + + +/************************************************************************** + * + * Private Functions - not intended for general user consumption.... + * + **************************************************************************/ + + +#if (GCC_VERSION >= 40300) && (GCC_VERSION < 40302) +#error "Buggy GCC 4.3.0 compiler, please upgrade!" +#endif + + +// USB Device Interrupt - handle all device-level events +// the transmit buffer flushing is triggered by the start of frame +// +ISR(USB_GEN_vect) +{ + uint8_t intbits, t; + + intbits = UDINT; + UDINT = 0; + if (intbits & (1<= NUM_DESC_LIST) { + UECONX = (1< desc_length) len = desc_length; + do { + // wait for host ready for IN packet + do { + i = UEINTX; + } while (!(i & ((1<= 1 && i <= MAX_ENDPOINT) { + usb_send_in(); + UENUM = i; + if (bRequest == SET_FEATURE) { + UECONX = (1< + +void usb_init(void); // initialize everything +uint8_t usb_configured(void); // is the USB port configured +int8_t usb_rawhid_recv(uint8_t *buffer, uint8_t timeout); // receive a packet, with timeout +int8_t usb_rawhid_send(const uint8_t *buffer, uint8_t timeout); // send a packet, with timeout + +// This file does not include the HID debug functions, so these empty +// macros replace them with nothing, so users can compile code that +// has calls to these functions. +#define usb_debug_putchar(c) +#define usb_debug_flush_output() + + +// Everything below this point is only intended for usb_serial.c +#ifdef USB_PRIVATE_INCLUDE +#include +#include +#include + +#define EP_TYPE_CONTROL 0x00 +#define EP_TYPE_BULK_IN 0x81 +#define EP_TYPE_BULK_OUT 0x80 +#define EP_TYPE_INTERRUPT_IN 0xC1 +#define EP_TYPE_INTERRUPT_OUT 0xC0 +#define EP_TYPE_ISOCHRONOUS_IN 0x41 +#define EP_TYPE_ISOCHRONOUS_OUT 0x40 + +#define EP_SINGLE_BUFFER 0x02 +#define EP_DOUBLE_BUFFER 0x06 + +#define EP_SIZE(s) ((s) > 32 ? 0x30 : \ + ((s) > 16 ? 0x20 : \ + ((s) > 8 ? 0x10 : \ + 0x00))) + +#define MAX_ENDPOINT 4 + +#define LSB(n) (n & 255) +#define MSB(n) ((n >> 8) & 255) + +#if defined(__AVR_AT90USB162__) +#define HW_CONFIG() +#define PLL_CONFIG() (PLLCSR = ((1<