*/
#include "libaltos.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define USE_POLL
+
+PUBLIC int
+altos_init(void)
+{
+ return LIBALTOS_SUCCESS;
+}
+
+PUBLIC void
+altos_fini(void)
+{
+}
+
+#ifdef DARWIN
+
+#undef USE_POLL
+
+/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
+static char *
+altos_strndup (const char *s, size_t n)
+{
+ size_t len = strlen (s);
+ char *ret;
+
+ if (len <= n)
+ return strdup (s);
+ ret = malloc(n + 1);
+ strncpy(ret, s, n);
+ ret[n] = '\0';
+ return ret;
+}
+
+#else
+#define altos_strndup strndup
+#endif
+
+/*
+ * Scan for Altus Metrum devices by looking through /sys
+ */
+
+#ifdef LINUX
-#define USE_DARWIN
+#define _GNU_SOURCE
+#include <ctype.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *
+cc_fullname (char *dir, char *file)
+{
+ char *new;
+ int dlen = strlen (dir);
+ int flen = strlen (file);
+ int slen = 0;
+
+ if (dir[dlen-1] != '/')
+ slen = 1;
+ new = malloc (dlen + slen + flen + 1);
+ if (!new)
+ return 0;
+ strcpy(new, dir);
+ if (slen)
+ strcat (new, "/");
+ strcat(new, file);
+ return new;
+}
+
+static char *
+cc_basename(char *file)
+{
+ char *b;
+
+ b = strrchr(file, '/');
+ if (!b)
+ return file;
+ return b + 1;
+}
+
+static char *
+load_string(char *dir, char *file)
+{
+ char *full = cc_fullname(dir, file);
+ char line[4096];
+ char *r;
+ FILE *f;
+ int rlen;
+
+ f = fopen(full, "r");
+ free(full);
+ if (!f)
+ return NULL;
+ r = fgets(line, sizeof (line), f);
+ fclose(f);
+ if (!r)
+ return NULL;
+ rlen = strlen(r);
+ if (r[rlen-1] == '\n')
+ r[rlen-1] = '\0';
+ return strdup(r);
+}
+
+static int
+load_hex(char *dir, char *file)
+{
+ char *line;
+ char *end;
+ long i;
-#ifdef USE_DARWIN
+ line = load_string(dir, file);
+ if (!line)
+ return -1;
+ i = strtol(line, &end, 16);
+ free(line);
+ if (end == line)
+ return -1;
+ return i;
+}
+
+static int
+load_dec(char *dir, char *file)
+{
+ char *line;
+ char *end;
+ long i;
+
+ line = load_string(dir, file);
+ if (!line)
+ return -1;
+ i = strtol(line, &end, 10);
+ free(line);
+ if (end == line)
+ return -1;
+ return i;
+}
+
+static int
+dir_filter_tty_colon(const struct dirent *d)
+{
+ return strncmp(d->d_name, "tty:", 4) == 0;
+}
+
+static int
+dir_filter_tty(const struct dirent *d)
+{
+ return strncmp(d->d_name, "tty", 3) == 0;
+}
+
+struct altos_usbdev {
+ char *sys;
+ char *tty;
+ char *manufacturer;
+ char *product_name;
+ int serial; /* AltOS always uses simple integer serial numbers */
+ int idProduct;
+ int idVendor;
+};
+
+static char *
+usb_tty(char *sys)
+{
+ char *base;
+ int num_configs;
+ int config;
+ struct dirent **namelist;
+ int interface;
+ int num_interfaces;
+ char endpoint_base[20];
+ char *endpoint_full;
+ char *tty_dir;
+ int ntty;
+ char *tty;
+
+ base = cc_basename(sys);
+ num_configs = load_hex(sys, "bNumConfigurations");
+ num_interfaces = load_hex(sys, "bNumInterfaces");
+ for (config = 1; config <= num_configs; config++) {
+ for (interface = 0; interface < num_interfaces; interface++) {
+ sprintf(endpoint_base, "%s:%d.%d",
+ base, config, interface);
+ endpoint_full = cc_fullname(sys, endpoint_base);
+
+ /* Check for tty:ttyACMx style names
+ */
+ ntty = scandir(endpoint_full, &namelist,
+ dir_filter_tty_colon,
+ alphasort);
+ if (ntty > 0) {
+ free(endpoint_full);
+ tty = cc_fullname("/dev", namelist[0]->d_name + 4);
+ free(namelist);
+ return tty;
+ }
+
+ /* Check for tty/ttyACMx style names
+ */
+ tty_dir = cc_fullname(endpoint_full, "tty");
+ free(endpoint_full);
+ ntty = scandir(tty_dir, &namelist,
+ dir_filter_tty,
+ alphasort);
+ free (tty_dir);
+ if (ntty > 0) {
+ tty = cc_fullname("/dev", namelist[0]->d_name);
+ free(namelist);
+ return tty;
+ }
+ }
+ }
+ return NULL;
+}
+
+static struct altos_usbdev *
+usb_scan_device(char *sys)
+{
+ struct altos_usbdev *usbdev;
+
+ usbdev = calloc(1, sizeof (struct altos_usbdev));
+ if (!usbdev)
+ return NULL;
+ usbdev->sys = strdup(sys);
+ usbdev->manufacturer = load_string(sys, "manufacturer");
+ usbdev->product_name = load_string(sys, "product");
+ usbdev->serial = load_dec(sys, "serial");
+ usbdev->idProduct = load_hex(sys, "idProduct");
+ usbdev->idVendor = load_hex(sys, "idVendor");
+ usbdev->tty = usb_tty(sys);
+ return usbdev;
+}
+
+static void
+usbdev_free(struct altos_usbdev *usbdev)
+{
+ free(usbdev->sys);
+ free(usbdev->manufacturer);
+ free(usbdev->product_name);
+ /* this can get used as a return value */
+ if (usbdev->tty)
+ free(usbdev->tty);
+ free(usbdev);
+}
+
+#define USB_DEVICES "/sys/bus/usb/devices"
+
+static int
+dir_filter_dev(const struct dirent *d)
+{
+ const char *n = d->d_name;
+ char c;
+
+ while ((c = *n++)) {
+ if (isdigit(c))
+ continue;
+ if (c == '-')
+ continue;
+ if (c == '.' && n != d->d_name + 1)
+ continue;
+ return 0;
+ }
+ return 1;
+}
+
+struct altos_list {
+ struct altos_usbdev **dev;
+ int current;
+ int ndev;
+};
+
+struct altos_list *
+altos_list_start(void)
+{
+ int e;
+ struct dirent **ents;
+ char *dir;
+ struct altos_usbdev *dev;
+ struct altos_list *devs;
+ int n;
+
+ devs = calloc(1, sizeof (struct altos_list));
+ if (!devs)
+ return NULL;
+
+ n = scandir (USB_DEVICES, &ents,
+ dir_filter_dev,
+ alphasort);
+ if (!n)
+ return 0;
+ for (e = 0; e < n; e++) {
+ dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
+ dev = usb_scan_device(dir);
+ free(dir);
+ if (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) {
+ if (devs->dev)
+ devs->dev = realloc(devs->dev,
+ devs->ndev + 1 * sizeof (struct usbdev *));
+ else
+ devs->dev = malloc (sizeof (struct usbdev *));
+ devs->dev[devs->ndev++] = dev;
+ }
+ }
+ free(ents);
+ devs->current = 0;
+ return devs;
+}
+
+int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+ struct altos_usbdev *dev;
+ if (list->current >= list->ndev)
+ return 0;
+ dev = list->dev[list->current];
+ strcpy(device->name, dev->product_name);
+ device->vendor = dev->idVendor;
+ device->product = dev->idProduct;
+ strcpy(device->path, dev->tty);
+ device->serial = dev->serial;
+ list->current++;
+ return 1;
+}
+
+void
+altos_list_finish(struct altos_list *usbdevs)
+{
+ int i;
+
+ if (!usbdevs)
+ return;
+ for (i = 0; i < usbdevs->ndev; i++)
+ usbdev_free(usbdevs->dev[i]);
+ free(usbdevs);
+}
+
+#endif
+
+#ifdef DARWIN
#include <IOKitLib.h>
#include <IOKit/usb/USBspec.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <termios.h>
-#include <errno.h>
struct altos_list {
- io_iterator_t iterator;
+ io_iterator_t iterator;
};
static int
get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
{
- CFTypeRef entry_as_string;
- Boolean got_string;
-
- entry_as_string = IORegistryEntrySearchCFProperty (object,
- kIOServicePlane,
- entry,
- kCFAllocatorDefault,
- kIORegistryIterateRecursively);
- if (entry_as_string) {
- got_string = CFStringGetCString(entry_as_string,
- result, result_len,
- kCFStringEncodingASCII);
-
- CFRelease(entry_as_string);
- if (got_string)
- return 1;
- }
- return 0;
-}
+ CFTypeRef entry_as_string;
+ Boolean got_string;
-int
-altos_init(void)
-{
- return 1;
+ entry_as_string = IORegistryEntrySearchCFProperty (object,
+ kIOServicePlane,
+ entry,
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively);
+ if (entry_as_string) {
+ got_string = CFStringGetCString(entry_as_string,
+ result, result_len,
+ kCFStringEncodingASCII);
+
+ CFRelease(entry_as_string);
+ if (got_string)
+ return 1;
+ }
+ return 0;
}
-void
-altos_fini(void)
+static int
+get_number(io_object_t object, CFStringRef entry, int *result)
{
+ CFTypeRef entry_as_number;
+ Boolean got_number;
+
+ entry_as_number = IORegistryEntrySearchCFProperty (object,
+ kIOServicePlane,
+ entry,
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively);
+ if (entry_as_number) {
+ got_number = CFNumberGetValue(entry_as_number,
+ kCFNumberIntType,
+ result);
+ if (got_number)
+ return 1;
+ }
+ return 0;
}
struct altos_list *
{
struct altos_list *list = calloc (sizeof (struct altos_list), 1);
CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
- UInt32 vendor = 0xfffe, product = 0x000a;
- CFNumberRef vendor_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor);
- CFNumberRef product_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product);
io_iterator_t tdIterator;
io_object_t tdObject;
-
- CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBVendorID), vendor_ref);
- CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBProductID), product_ref);
+ kern_return_t ret;
+ int i;
- IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
-
- CFRelease(vendor_ref);
- CFRelease(product_ref);
+ ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
+ if (ret != kIOReturnSuccess)
+ return NULL;
return list;
}
if (!object)
return 0;
+ if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
+ !get_number (object, CFSTR(kUSBProductID), &device->product))
+ continue;
+ if (device->vendor != 0xfffe)
+ continue;
+ if (device->product < 0x000a || 0x0013 < device->product)
+ continue;
if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
- get_string (object, CFSTR("USB Product Name"), device->product, sizeof (device->product)) &&
+ get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
device->serial = atoi(serial_string);
return 1;
void
altos_list_finish(struct altos_list *list)
{
- IOObjectRelease (list->iterator);
- free(list);
+ IOObjectRelease (list->iterator);
+ free(list);
}
+#endif
+
+#ifdef POSIX_TTY
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <errno.h>
#define USB_BUF_SIZE 64
struct altos_file {
int fd;
+#ifdef USE_POLL
+ int pipe[2];
+#else
+ int out_fd;
+#endif
unsigned char out_data[USB_BUF_SIZE];
int out_used;
unsigned char in_data[USB_BUF_SIZE];
int in_read;
};
-void
-altos_test(char *path)
-{
- int n;
- char buf[16];
- int fd;
- struct termios term;
-
- fd = open(path, O_RDWR | O_NOCTTY);
- if (fd < 0) {
- perror(path);
- return;
- }
- if (ioctl(fd, TIOCEXCL, (char *) 0) < 0) {
- perror("TIOCEXCL");
- close (fd);
- return;
- }
-
- n = tcgetattr(fd, &term);
- if (n < 0) {
- perror("tcgetattr");
- close(fd);
- return;
- }
- cfmakeraw(&term);
- term.c_cc[VMIN] = 0;
- term.c_cc[VTIME] = 1;
- n = tcsetattr(fd, TCSAFLUSH, &term);
- if (n < 0) {
- perror("tcsetattr");
- close(fd);
- return;
- }
- write(fd, "\n?\n", 3);
- for (;;) {
- n = read(fd, buf, sizeof (buf));
- if (n < 0) {
- perror("read");
- break;
- }
- if (n == 0)
- break;
- write(1, buf, n);
- }
- close(fd);
-}
-
-struct altos_file *
+PUBLIC struct altos_file *
altos_open(struct altos_device *device)
{
struct altos_file *file = calloc (sizeof (struct altos_file), 1);
free(file);
return NULL;
}
+#ifdef USE_POLL
+ pipe(file->pipe);
+#else
+ file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
+ if (file->out_fd < 0) {
+ perror(device->path);
+ close(file->fd);
+ free(file);
+ return NULL;
+ }
+#endif
ret = tcgetattr(file->fd, &term);
if (ret < 0) {
perror("tcgetattr");
close(file->fd);
+#ifndef USE_POLL
+ close(file->out_fd);
+#endif
free(file);
return NULL;
}
cfmakeraw(&term);
+#ifdef USE_POLL
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+#else
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 1;
+#endif
ret = tcsetattr(file->fd, TCSAFLUSH, &term);
if (ret < 0) {
perror("tcsetattr");
close(file->fd);
+#ifndef USE_POLL
+ close(file->out_fd);
+#endif
free(file);
return NULL;
}
return file;
}
-void
+PUBLIC void
altos_close(struct altos_file *file)
{
- close(file->fd);
+ if (file->fd != -1) {
+ int fd = file->fd;
+ file->fd = -1;
+#ifdef USE_POLL
+ write(file->pipe[1], "\r", 1);
+#else
+ close(file->out_fd);
+ file->out_fd = -1;
+#endif
+ close(fd);
+ }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+ altos_close(file);
free(file);
}
-int
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+ if (file->out_used && 0) {
+ printf ("flush \"");
+ fwrite(file->out_data, 1, file->out_used, stdout);
+ printf ("\"\n");
+ }
+ while (file->out_used) {
+ int ret;
+
+ if (file->fd < 0)
+ return -EBADF;
+#ifdef USE_POLL
+ ret = write (file->fd, file->out_data, file->out_used);
+#else
+ ret = write (file->out_fd, file->out_data, file->out_used);
+#endif
+ if (ret < 0)
+ return -errno;
+ if (ret) {
+ memmove(file->out_data, file->out_data + ret,
+ file->out_used - ret);
+ file->out_used -= ret;
+ }
+ }
+ return 0;
+}
+
+PUBLIC int
altos_putchar(struct altos_file *file, char c)
{
int ret;
if (file->out_used == USB_BUF_SIZE) {
ret = altos_flush(file);
- if (ret)
+ if (ret) {
return ret;
+ }
}
file->out_data[file->out_used++] = c;
+ ret = 0;
if (file->out_used == USB_BUF_SIZE)
- return altos_flush(file);
+ ret = altos_flush(file);
return 0;
}
-int
-altos_flush(struct altos_file *file)
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
+static int
+altos_fill(struct altos_file *file, int timeout)
{
- while (file->out_used) {
- int ret;
+ int ret;
+#ifdef USE_POLL
+ struct pollfd fd[2];
+#endif
- ret = write (file->fd, file->out_data, file->out_used);
- if (ret < 0)
- return -errno;
- if (ret) {
- memmove(file->out_data, file->out_data + ret,
- file->out_used - ret);
- file->out_used -= ret;
+ if (timeout == 0)
+ timeout = -1;
+ while (file->in_read == file->in_used) {
+ if (file->fd < 0)
+ return LIBALTOS_ERROR;
+#ifdef USE_POLL
+ fd[0].fd = file->fd;
+ fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
+ fd[1].fd = file->pipe[0];
+ fd[1].events = POLLIN;
+ ret = poll(fd, 2, timeout);
+ if (ret < 0) {
+ perror("altos_getchar");
+ return LIBALTOS_ERROR;
+ }
+ if (ret == 0)
+ return LIBALTOS_TIMEOUT;
+
+ if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
+ return LIBALTOS_ERROR;
+ if (fd[0].revents & POLLIN)
+#endif
+ {
+ ret = read(file->fd, file->in_data, USB_BUF_SIZE);
+ if (ret < 0) {
+ perror("altos_getchar");
+ return LIBALTOS_ERROR;
+ }
+ file->in_read = 0;
+ file->in_used = ret;
+#ifndef USE_POLL
+ if (ret == 0 && timeout > 0)
+ return LIBALTOS_TIMEOUT;
+#endif
}
}
+ if (file->in_used && 0) {
+ printf ("fill \"");
+ fwrite(file->in_data, 1, file->in_used, stdout);
+ printf ("\"\n");
+ }
+ return 0;
}
-int
+PUBLIC int
altos_getchar(struct altos_file *file, int timeout)
{
+ int ret;
while (file->in_read == file->in_used) {
- int ret;
-
- altos_flush(file);
- ret = read(file->fd, file->in_data, USB_BUF_SIZE);
- if (ret < 0)
- return -errno;
- file->in_read = 0;
- file->in_used = ret;
+ if (file->fd < 0)
+ return LIBALTOS_ERROR;
+ ret = altos_fill(file, timeout);
+ if (ret)
+ return ret;
}
return file->in_data[file->in_read++];
}
-#endif /* USE_DARWIN */
+#endif /* POSIX_TTY */
+
+#ifdef WINDOWS
-#ifdef USE_LIBUSB
-#include <libusb.h>
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
+#include <windows.h>
+#include <setupapi.h>
+
+struct altos_list {
+ HDEVINFO dev_info;
+ int index;
+};
-libusb_context *usb_context;
+#define USB_BUF_SIZE 64
-int altos_init(void)
+struct altos_file {
+ HANDLE handle;
+ unsigned char out_data[USB_BUF_SIZE];
+ int out_used;
+ unsigned char in_data[USB_BUF_SIZE];
+ int in_used;
+ int in_read;
+ OVERLAPPED ov_read;
+ BOOL pend_read;
+ OVERLAPPED ov_write;
+};
+
+PUBLIC struct altos_list *
+altos_list_start(void)
{
- int ret;
- ret = libusb_init(&usb_context);
- if (ret)
- return ret;
- libusb_set_debug(usb_context, 3);
- return 0;
+ struct altos_list *list = calloc(1, sizeof (struct altos_list));
+
+ if (!list)
+ return NULL;
+ list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
+ DIGCF_ALLCLASSES|DIGCF_PRESENT);
+ if (list->dev_info == INVALID_HANDLE_VALUE) {
+ printf("SetupDiGetClassDevs failed %d\n", GetLastError());
+ free(list);
+ return NULL;
+ }
+ list->index = 0;
+ return list;
}
-void altos_fini(void)
+PUBLIC int
+altos_list_next(struct altos_list *list, struct altos_device *device)
{
- libusb_exit(usb_context);
- usb_context = NULL;
+ SP_DEVINFO_DATA dev_info_data;
+ char port[128];
+ DWORD port_len;
+ char friendlyname[256];
+ char symbolic[256];
+ DWORD symbolic_len;
+ HKEY dev_key;
+ int vid, pid;
+ int serial;
+ HRESULT result;
+ DWORD friendlyname_type;
+ DWORD friendlyname_len;
+
+ dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
+ while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
+ &dev_info_data))
+ {
+ list->index++;
+
+ dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
+ DICS_FLAG_GLOBAL, 0, DIREG_DEV,
+ KEY_READ);
+ if (dev_key == INVALID_HANDLE_VALUE) {
+ printf("cannot open device registry key\n");
+ continue;
+ }
+
+ /* Fetch symbolic name for this device and parse out
+ * the vid/pid/serial info */
+ symbolic_len = sizeof(symbolic);
+ result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
+ symbolic, &symbolic_len);
+ if (result != 0) {
+ printf("cannot find SymbolicName value\n");
+ RegCloseKey(dev_key);
+ continue;
+ }
+ vid = pid = serial = 0;
+ sscanf(symbolic + sizeof("\\??\\USB#VID_") - 1,
+ "%04X", &vid);
+ sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
+ "%04X", &pid);
+ sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
+ "%d", &serial);
+ if (!USB_IS_ALTUSMETRUM(vid, pid)) {
+ RegCloseKey(dev_key);
+ continue;
+ }
+
+ /* Fetch the com port name */
+ port_len = sizeof (port);
+ result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
+ port, &port_len);
+ RegCloseKey(dev_key);
+ if (result != 0) {
+ printf("failed to get PortName\n");
+ continue;
+ }
+
+ /* Fetch the device description which is the device name,
+ * with firmware that has unique USB ids */
+ friendlyname_len = sizeof (friendlyname);
+ if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
+ &dev_info_data,
+ SPDRP_FRIENDLYNAME,
+ &friendlyname_type,
+ (BYTE *)friendlyname,
+ sizeof(friendlyname),
+ &friendlyname_len))
+ {
+ printf("Failed to get friendlyname\n");
+ continue;
+ }
+ device->vendor = vid;
+ device->product = pid;
+ device->serial = serial;
+ strcpy(device->name, friendlyname);
+
+ strcpy(device->path, port);
+ return 1;
+ }
+ result = GetLastError();
+ if (result != ERROR_NO_MORE_ITEMS)
+ printf ("SetupDiEnumDeviceInfo failed error %d\n", result);
+ return 0;
}
-static libusb_device **list;
-static ssize_t num, current;
+PUBLIC void
+altos_list_finish(struct altos_list *list)
+{
+ SetupDiDestroyDeviceInfoList(list->dev_info);
+ free(list);
+}
-int altos_list_start(void)
+static int
+altos_queue_read(struct altos_file *file)
{
- if (list)
- altos_list_finish();
- current = 0;
- num = libusb_get_device_list(usb_context, &list);
- if (num == 0) {
- current = num = 0;
- list = NULL;
- return 0;
+ DWORD got;
+ if (file->pend_read)
+ return LIBALTOS_SUCCESS;
+
+ if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
+ if (GetLastError() != ERROR_IO_PENDING)
+ return LIBALTOS_ERROR;
+ file->pend_read = TRUE;
+ } else {
+ file->pend_read = FALSE;
+ file->in_read = 0;
+ file->in_used = got;
}
- return 1;
+ return LIBALTOS_SUCCESS;
}
-int altos_list_next(struct altos_device *device)
-{
- while (current < num) {
- struct libusb_device_descriptor descriptor;
- libusb_device *usb_device = list[current++];
-
- if (libusb_get_device_descriptor(usb_device, &descriptor) == 0) {
- if (descriptor.idVendor == 0xfffe)
- {
- libusb_device_handle *handle;
- if (libusb_open(usb_device, &handle) == 0) {
- char serial_number[256];
- libusb_get_string_descriptor_ascii(handle, descriptor.iProduct,
- device->product,
- sizeof(device->product));
- libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber,
- serial_number,
- sizeof (serial_number));
- libusb_close(handle);
- device->serial = atoi(serial_number);
- device->device = usb_device;
- return 1;
- }
- }
- }
+static int
+altos_wait_read(struct altos_file *file, int timeout)
+{
+ DWORD ret;
+ DWORD got;
+
+ if (!file->pend_read)
+ return LIBALTOS_SUCCESS;
+
+ if (!timeout)
+ timeout = INFINITE;
+
+ ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
+ switch (ret) {
+ case WAIT_OBJECT_0:
+ if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE))
+ return LIBALTOS_ERROR;
+ file->pend_read = FALSE;
+ file->in_read = 0;
+ file->in_used = got;
+ break;
+ case WAIT_TIMEOUT:
+ return LIBALTOS_TIMEOUT;
+ break;
+ default:
+ return LIBALTOS_ERROR;
}
- return 0;
+ return LIBALTOS_SUCCESS;
}
-void altos_list_finish(void)
+static int
+altos_fill(struct altos_file *file, int timeout)
{
- if (list) {
- libusb_free_device_list(list, 1);
- list = NULL;
- }
+ int ret;
+
+ if (file->in_read < file->in_used)
+ return LIBALTOS_SUCCESS;
+
+ file->in_read = file->in_used = 0;
+
+ ret = altos_queue_read(file);
+ if (ret)
+ return ret;
+ ret = altos_wait_read(file, timeout);
+ if (ret)
+ return ret;
+
+ return LIBALTOS_SUCCESS;
}
-#define USB_BUF_SIZE 64
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+ DWORD put;
+ char *data = file->out_data;
+ char used = file->out_used;
+ DWORD ret;
-struct altos_file {
- struct libusb_device *device;
- struct libusb_device_handle *handle;
- int out_ep;
- int out_size;
- int in_ep;
- int in_size;
- unsigned char out_data[USB_BUF_SIZE];
- int out_used;
- unsigned char in_data[USB_BUF_SIZE];
- int in_used;
- int in_read;
-};
+ while (used) {
+ if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
+ if (GetLastError() != ERROR_IO_PENDING)
+ return LIBALTOS_ERROR;
+ ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
+ switch (ret) {
+ case WAIT_OBJECT_0:
+ if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE))
+ return LIBALTOS_ERROR;
+ break;
+ default:
+ return LIBALTOS_ERROR;
+ }
+ }
+ data += put;
+ used -= put;
+ }
+ file->out_used = 0;
+ return LIBALTOS_SUCCESS;
+}
-struct altos_file *
+PUBLIC struct altos_file *
altos_open(struct altos_device *device)
{
- struct altos_file *file;
- struct libusb_device_handle *handle;
- if (libusb_open(device->device, &handle) == 0) {
- int ret;
+ struct altos_file *file = calloc (1, sizeof (struct altos_file));
+ char full_name[64];
+ DCB dcbSerialParams = {0};
+ COMMTIMEOUTS timeouts;
- ret = libusb_claim_interface(handle, 1);
-#if 0
- if (ret) {
- libusb_close(handle);
- return NULL;
- }
-#endif
- ret = libusb_detach_kernel_driver(handle, 1);
-#if 0
- if (ret) {
- libusb_close(handle);
- return NULL;
- }
-#endif
+ if (!file)
+ return NULL;
+
+ strcpy(full_name, "\\\\.\\");
+ strcat(full_name, device->path);
+ file->handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL);
+ if (file->handle == INVALID_HANDLE_VALUE) {
+ free(file);
+ return NULL;
+ }
+ file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- file = calloc(sizeof (struct altos_file), 1);
- file->device = libusb_ref_device(device->device);
- file->handle = handle;
- /* XXX should get these from the endpoint descriptors */
- file->out_ep = 4 | LIBUSB_ENDPOINT_OUT;
- file->out_size = 64;
- file->in_ep = 5 | LIBUSB_ENDPOINT_IN;
- file->in_size = 64;
+ timeouts.ReadIntervalTimeout = MAXDWORD;
+ timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+ timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */
+ timeouts.WriteTotalTimeoutMultiplier = 0;
+ timeouts.WriteTotalTimeoutConstant = 0;
+ SetCommTimeouts(file->handle, &timeouts);
- return file;
+ dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
+ if (!GetCommState(file->handle, &dcbSerialParams)) {
+ CloseHandle(file->handle);
+ free(file);
+ return NULL;
}
- return NULL;
+ dcbSerialParams.BaudRate = CBR_9600;
+ dcbSerialParams.ByteSize = 8;
+ dcbSerialParams.StopBits = ONESTOPBIT;
+ dcbSerialParams.Parity = NOPARITY;
+ if (!SetCommState(file->handle, &dcbSerialParams)) {
+ CloseHandle(file->handle);
+ free(file);
+ return NULL;
+ }
+
+ return file;
}
-void
+PUBLIC void
altos_close(struct altos_file *file)
{
- libusb_close(file->handle);
- libusb_unref_device(file->device);
- file->handle = NULL;
+ if (file->handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(file->handle);
+ file->handle = INVALID_HANDLE_VALUE;
+ }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+ altos_close(file);
free(file);
}
{
int ret;
- if (file->out_used == file->out_size) {
+ if (file->out_used == USB_BUF_SIZE) {
ret = altos_flush(file);
if (ret)
return ret;
}
file->out_data[file->out_used++] = c;
- if (file->out_used == file->out_size)
+ if (file->out_used == USB_BUF_SIZE)
return altos_flush(file);
- return 0;
-}
-
-int
-altos_flush(struct altos_file *file)
-{
- while (file->out_used) {
- int transferred;
- int ret;
-
- ret = libusb_bulk_transfer(file->handle,
- file->out_ep,
- file->out_data,
- file->out_used,
- &transferred,
- 0);
- if (ret)
- return ret;
- if (transferred) {
- memmove(file->out_data, file->out_data + transferred,
- file->out_used - transferred);
- file->out_used -= transferred;
- }
- }
+ return LIBALTOS_SUCCESS;
}
int
altos_getchar(struct altos_file *file, int timeout)
{
+ int ret;
while (file->in_read == file->in_used) {
- int ret;
- int transferred;
-
- altos_flush(file);
- ret = libusb_bulk_transfer(file->handle,
- file->in_ep,
- file->in_data,
- file->in_size,
- &transferred,
- (unsigned int) timeout);
+ if (file->handle == INVALID_HANDLE_VALUE)
+ return LIBALTOS_ERROR;
+ ret = altos_fill(file, timeout);
if (ret)
return ret;
- file->in_read = 0;
- file->in_used = transferred;
}
return file->in_data[file->in_read++];
}
-#endif /* USE_LIBUSB */
+#endif