X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=libaltos%2Flibaltos.c;fp=libaltos%2Flibaltos.c;h=0000000000000000000000000000000000000000;hp=ebef2e2107cad4dd5e9263c85562ead00bbe0ed4;hb=1594691ea88ca84634eea237ac8137a5bdc19f5c;hpb=afba05c41f30c9273668d5ed71e0dc8c1ca53141 diff --git a/libaltos/libaltos.c b/libaltos/libaltos.c deleted file mode 100644 index ebef2e21..00000000 --- a/libaltos/libaltos.c +++ /dev/null @@ -1,1536 +0,0 @@ -/* - * Copyright © 2010 Keith Packard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "libaltos.h" -#include -#include -#include - -#define BLUETOOTH_PRODUCT_TELEBT "TeleBT" - -#define USE_POLL - -PUBLIC int -altos_init(void) -{ - return LIBALTOS_SUCCESS; -} - -PUBLIC void -altos_fini(void) -{ -} - -static struct altos_error last_error; - -static void -altos_set_last_error(int code, char *string) -{ - last_error.code = code; - strncpy(last_error.string, string, sizeof (last_error.string) -1); - last_error.string[sizeof(last_error.string)-1] = '\0'; -} - -PUBLIC void -altos_get_last_error(struct altos_error *error) -{ - *error = last_error; -} - -#ifdef DARWIN - -#include - -#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 - -#ifdef POSIX_TTY - -#include -#include -#include -#include -#include -#include - -#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_used; - int in_read; -}; - -static void -altos_set_last_posix_error(void) -{ - altos_set_last_error(errno, strerror(errno)); -} - -PUBLIC struct altos_file * -altos_open(struct altos_device *device) -{ - struct altos_file *file = calloc (sizeof (struct altos_file), 1); - int ret; - struct termios term; - - if (!file) { - altos_set_last_posix_error(); - return NULL; - } - -// altos_set_last_error(12, "yeah yeah, failed again"); -// free(file); -// return NULL; - - file->fd = open(device->path, O_RDWR | O_NOCTTY); - if (file->fd < 0) { - altos_set_last_posix_error(); - 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) { - altos_set_last_posix_error(); - close(file->fd); - free(file); - return NULL; - } -#endif - ret = tcgetattr(file->fd, &term); - if (ret < 0) { - altos_set_last_posix_error(); - close(file->fd); -#ifndef USE_POLL - close(file->out_fd); -#endif - free(file); - return NULL; - } - cfmakeraw(&term); - cfsetospeed(&term, B9600); - cfsetispeed(&term, B9600); -#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) { - altos_set_last_posix_error(); - close(file->fd); -#ifndef USE_POLL - close(file->out_fd); -#endif - free(file); - return NULL; - } - return file; -} - -PUBLIC void -altos_close(struct altos_file *file) -{ - 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); -} - -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) { - altos_set_last_posix_error(); - return -last_error.code; - } - 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) { - return ret; - } - } - file->out_data[file->out_used++] = c; - ret = 0; - if (file->out_used == USB_BUF_SIZE) - ret = altos_flush(file); - return ret; -} - -#ifdef USE_POLL -#include -#endif - -static int -altos_fill(struct altos_file *file, int timeout) -{ - int ret; -#ifdef USE_POLL - struct pollfd fd[2]; -#endif - - 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) { - altos_set_last_posix_error(); - 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) { - altos_set_last_posix_error(); - 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; -} - -PUBLIC int -altos_getchar(struct altos_file *file, int timeout) -{ - int ret; - while (file->in_read == file->in_used) { - if (file->fd < 0) - return LIBALTOS_ERROR; - ret = altos_fill(file, timeout); - if (ret) - return ret; - } - return file->in_data[file->in_read++]; -} - -#endif /* POSIX_TTY */ - -/* - * Scan for Altus Metrum devices by looking through /sys - */ - -#ifdef LINUX - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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; - - 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"); - ntty = scandir(tty_dir, &namelist, - dir_filter_tty, - alphasort); - free (tty_dir); - if (ntty > 0) { - tty = cc_fullname("/dev", namelist[0]->d_name); - free(endpoint_full); - free(namelist); - return tty; - } - - /* Check for ttyACMx style names - */ - ntty = scandir(endpoint_full, &namelist, - dir_filter_tty, - alphasort); - free(endpoint_full); - 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; - char *tty; - - tty = usb_tty(sys); - if (!tty) - return NULL; - 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 = tty; - 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); - if (!dev) - continue; - free(dir); - 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; -} - -PUBLIC struct altos_list * -altos_ftdi_list_start(void) -{ - return altos_list_start(); -} - -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); -} - -#include - -static void *libbt; -static int bt_initialized; - -static int init_bt(void) { - if (!bt_initialized) { - bt_initialized = 1; - libbt = dlopen("libbluetooth.so.3", RTLD_LAZY); - if (!libbt) - printf("failed to find bluetooth library\n"); - } - return libbt != NULL; -} - -#define join(a,b) a ## b -#define bt_func(name, ret, fail, formals, actuals) \ - static ret join(altos_, name) formals { \ - static ret (*name) formals; \ - if (!init_bt()) return fail; \ - name = dlsym(libbt, #name); \ - if (!name) return fail; \ - return name actuals; \ - } - -bt_func(ba2str, int, -1, (const bdaddr_t *ba, char *str), (ba, str)) -#define ba2str altos_ba2str - -bt_func(str2ba, int, -1, (const char *str, bdaddr_t *ba), (str, ba)) -#define str2ba altos_str2ba - -bt_func(hci_read_remote_name, int, -1, (int sock, const bdaddr_t *ba, int len, char *name, int timeout), (sock, ba, len, name, timeout)) -#define hci_read_remote_name altos_hci_read_remote_name - -bt_func(hci_open_dev, int, -1, (int dev_id), (dev_id)) -#define hci_open_dev altos_hci_open_dev - -bt_func(hci_get_route, int, -1, (bdaddr_t *bdaddr), (bdaddr)) -#define hci_get_route altos_hci_get_route - -bt_func(hci_inquiry, int, -1, (int adapter_id, int len, int max_rsp, const uint8_t *lap, inquiry_info **devs, long flags), (adapter_id, len, max_rsp, lap, devs, flags)) -#define hci_inquiry altos_hci_inquiry - -struct altos_bt_list { - inquiry_info *ii; - int sock; - int dev_id; - int rsp; - int num_rsp; -}; - -#define INQUIRY_MAX_RSP 255 - -struct altos_bt_list * -altos_bt_list_start(int inquiry_time) -{ - struct altos_bt_list *bt_list; - - bt_list = calloc(1, sizeof (struct altos_bt_list)); - if (!bt_list) - goto no_bt_list; - - bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info)); - if (!bt_list->ii) - goto no_ii; - bt_list->dev_id = hci_get_route(NULL); - if (bt_list->dev_id < 0) - goto no_dev_id; - - bt_list->sock = hci_open_dev(bt_list->dev_id); - if (bt_list->sock < 0) - goto no_sock; - - bt_list->num_rsp = hci_inquiry(bt_list->dev_id, - inquiry_time, - INQUIRY_MAX_RSP, - NULL, - &bt_list->ii, - IREQ_CACHE_FLUSH); - if (bt_list->num_rsp < 0) - goto no_rsp; - - bt_list->rsp = 0; - return bt_list; - -no_rsp: - close(bt_list->sock); -no_sock: -no_dev_id: - free(bt_list->ii); -no_ii: - free(bt_list); -no_bt_list: - return NULL; -} - -int -altos_bt_list_next(struct altos_bt_list *bt_list, - struct altos_bt_device *device) -{ - inquiry_info *ii; - - if (bt_list->rsp >= bt_list->num_rsp) - return 0; - - ii = &bt_list->ii[bt_list->rsp]; - if (ba2str(&ii->bdaddr, device->addr) < 0) - return 0; - memset(&device->name, '\0', sizeof (device->name)); - if (hci_read_remote_name(bt_list->sock, &ii->bdaddr, - sizeof (device->name), - device->name, 0) < 0) { - strcpy(device->name, "[unknown]"); - } - bt_list->rsp++; - return 1; -} - -void -altos_bt_list_finish(struct altos_bt_list *bt_list) -{ - close(bt_list->sock); - free(bt_list->ii); - free(bt_list); -} - -void -altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device) -{ - strncpy(device->name, name, sizeof (device->name)); - device->name[sizeof(device->name)-1] = '\0'; - strncpy(device->addr, addr, sizeof (device->addr)); - device->addr[sizeof(device->addr)-1] = '\0'; -} - -struct altos_file * -altos_bt_open(struct altos_bt_device *device) -{ - struct sockaddr_rc addr = { 0 }; - int status, i; - struct altos_file *file; - - file = calloc(1, sizeof (struct altos_file)); - if (!file) { - errno = ENOMEM; - altos_set_last_posix_error(); - goto no_file; - } - addr.rc_family = AF_BLUETOOTH; - addr.rc_channel = 1; - if (str2ba(device->addr, &addr.rc_bdaddr) < 0) { - altos_set_last_posix_error(); - goto no_sock; - } - - for (i = 0; i < 5; i++) { - file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (file->fd < 0) { - altos_set_last_posix_error(); - goto no_sock; - } - - status = connect(file->fd, - (struct sockaddr *)&addr, - sizeof(addr)); - if (status >= 0 || errno != EBUSY) - break; - close(file->fd); - usleep(100 * 1000); - } - if (status < 0) { - altos_set_last_posix_error(); - goto no_link; - } - usleep(100 * 1000); - -#ifdef USE_POLL - pipe(file->pipe); -#else - file->out_fd = dup(file->fd); -#endif - return file; -no_link: - close(file->fd); -no_sock: - free(file); -no_file: - return NULL; -} - -#endif - -#ifdef DARWIN - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct altos_list { - io_iterator_t iterator; - int ftdi; -}; - -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; -} - -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; -} - -PUBLIC struct altos_list * -altos_list_start(void) -{ - struct altos_list *list = calloc (sizeof (struct altos_list), 1); - CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice"); - io_iterator_t tdIterator; - io_object_t tdObject; - kern_return_t ret; - int i; - - ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator); - if (ret != kIOReturnSuccess) { - free(list); - return NULL; - } - list->ftdi = 0; - return list; -} - -PUBLIC struct altos_list * -altos_ftdi_list_start(void) -{ - struct altos_list *list = altos_list_start(); - - if (list) - list->ftdi = 1; - return list; -} - -PUBLIC int -altos_list_next(struct altos_list *list, struct altos_device *device) -{ - io_object_t object; - char serial_string[128]; - - for (;;) { - object = IOIteratorNext(list->iterator); - if (!object) - return 0; - - if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) || - !get_number (object, CFSTR(kUSBProductID), &device->product)) - continue; - if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) && - 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; - } - } -} - -PUBLIC void -altos_list_finish(struct altos_list *list) -{ - IOObjectRelease (list->iterator); - free(list); -} - -struct altos_bt_list { - int sock; - int dev_id; - int rsp; - int num_rsp; -}; - -#define INQUIRY_MAX_RSP 255 - -struct altos_bt_list * -altos_bt_list_start(int inquiry_time) -{ - return NULL; -} - -int -altos_bt_list_next(struct altos_bt_list *bt_list, - struct altos_bt_device *device) -{ - return 0; -} - -void -altos_bt_list_finish(struct altos_bt_list *bt_list) -{ -} - -void -altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device) -{ - strncpy(device->name, name, sizeof (device->name)); - device->name[sizeof(device->name)-1] = '\0'; - strncpy(device->addr, addr, sizeof (device->addr)); - device->addr[sizeof(device->addr)-1] = '\0'; -} - -struct altos_file * -altos_bt_open(struct altos_bt_device *device) -{ - return NULL; -} - -#endif - - -#ifdef WINDOWS - -#include -#include -#include - -struct altos_list { - HDEVINFO dev_info; - int index; - int ftdi; -}; - -#define USB_BUF_SIZE 64 - -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; -}; - -#include - -static void -log_message(char *fmt, ...) -{ - static FILE *log = NULL; - va_list a; - - if (!log) - log = fopen("\\temp\\altos.txt", "w"); - if (log) { - SYSTEMTIME time; - GetLocalTime(&time); - fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ", - time.wYear, time.wMonth, time.wDay, - time.wHour, time.wMinute, time.wSecond); - va_start(a, fmt); - vfprintf(log, fmt, a); - va_end(a); - fflush(log); - } -} - -static void -_altos_set_last_windows_error(char *file, int line) -{ - DWORD error = GetLastError(); - TCHAR message[1024]; - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, - 0, - error, - 0, - message, - sizeof (message) / sizeof (TCHAR), - NULL); - if (error != ERROR_SUCCESS) - log_message ("%s:%d %s\n", file, line, message); - altos_set_last_error(error, message); -} - -#define altos_set_last_windows_error() _altos_set_last_windows_error(__FILE__, __LINE__) - -PUBLIC struct altos_list * -altos_list_start(void) -{ - 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) { - altos_set_last_windows_error(); - free(list); - return NULL; - } - list->index = 0; - list->ftdi = 0; - return list; -} - -PUBLIC struct altos_list * -altos_ftdi_list_start(void) -{ - struct altos_list *list = calloc(1, sizeof (struct altos_list)); - - if (!list) - return NULL; - list->dev_info = SetupDiGetClassDevs(NULL, "FTDIBUS", NULL, - DIGCF_ALLCLASSES|DIGCF_PRESENT); - if (list->dev_info == INVALID_HANDLE_VALUE) { - altos_set_last_windows_error(); - free(list); - return NULL; - } - list->index = 0; - list->ftdi = 1; - return list; -} - -PUBLIC int -altos_list_next(struct altos_list *list, struct altos_device *device) -{ - SP_DEVINFO_DATA dev_info_data; - BYTE port[128]; - DWORD port_len; - char friendlyname[256]; - BYTE symbolic[256]; - DWORD symbolic_len; - HKEY dev_key; - unsigned int vid, pid; - int serial; - HRESULT result; - DWORD friendlyname_type; - DWORD friendlyname_len; - char instanceid[1024]; - DWORD instanceid_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) { - altos_set_last_windows_error(); - continue; - } - - if (list->ftdi) { - vid = 0x0403; - pid = 0x6015; - serial = 0; - } else { - vid = pid = serial = 0; - /* 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) { - altos_set_last_windows_error(); - } else { - sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1, - "%04X", &vid); - sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1, - "%04X", &pid); - sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1, - "%d", &serial); - } - if (vid == 0 || pid == 0 || serial == 0) { - if (SetupDiGetDeviceInstanceId(list->dev_info, - &dev_info_data, - instanceid, - sizeof (instanceid), - &instanceid_len)) { - sscanf((char *) instanceid + sizeof("USB\\VID_") - 1, - "%04X", &vid); - sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_") - 1, - "%04X", &pid); - sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_XXXX\\") - 1, - "%d", &serial); - } else { - altos_set_last_windows_error(); - } - } - if (vid == 0 || pid == 0 || serial == 0) { - 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) { - altos_set_last_windows_error(); - 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)) - { - altos_set_last_windows_error(); - continue; - } - device->vendor = vid; - device->product = pid; - device->serial = serial; - strcpy(device->name, friendlyname); - - strcpy(device->path, (char *) port); - return 1; - } - result = GetLastError(); - if (result != ERROR_NO_MORE_ITEMS) - altos_set_last_windows_error(); - return 0; -} - -PUBLIC void -altos_list_finish(struct altos_list *list) -{ - SetupDiDestroyDeviceInfoList(list->dev_info); - free(list); -} - -static int -altos_queue_read(struct altos_file *file) -{ - 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) { - altos_set_last_windows_error(); - return LIBALTOS_ERROR; - } - file->pend_read = TRUE; - } else { - file->pend_read = FALSE; - file->in_read = 0; - file->in_used = got; - } - return LIBALTOS_SUCCESS; -} - -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)) { - altos_set_last_windows_error(); - return LIBALTOS_ERROR; - } - file->pend_read = FALSE; - file->in_read = 0; - file->in_used = got; - break; - case WAIT_TIMEOUT: - return LIBALTOS_TIMEOUT; - break; - default: - altos_set_last_windows_error(); - return LIBALTOS_ERROR; - } - return LIBALTOS_SUCCESS; -} - -static int -altos_fill(struct altos_file *file, int timeout) -{ - 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; -} - -PUBLIC int -altos_flush(struct altos_file *file) -{ - DWORD put; - unsigned char *data = file->out_data; - int used = file->out_used; - DWORD ret; - - while (used) { - if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) { - if (GetLastError() != ERROR_IO_PENDING) { - altos_set_last_windows_error(); - 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)) { - altos_set_last_windows_error(); - return LIBALTOS_ERROR; - } - break; - default: - altos_set_last_windows_error(); - return LIBALTOS_ERROR; - } - } - data += put; - used -= put; - } - file->out_used = 0; - return LIBALTOS_SUCCESS; -} - -static HANDLE -open_serial(char *full_name) -{ - HANDLE handle; - DCB dcb; - - handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); - - if (handle == INVALID_HANDLE_VALUE) { - altos_set_last_windows_error(); - return INVALID_HANDLE_VALUE; - } - - if (!GetCommState(handle, &dcb)) { - altos_set_last_windows_error(); - CloseHandle(handle); - return INVALID_HANDLE_VALUE; - } - dcb.BaudRate = CBR_9600; - dcb.fBinary = TRUE; - dcb.fParity = FALSE; - dcb.fOutxCtsFlow = FALSE; - dcb.fOutxDsrFlow = FALSE; - dcb.fDtrControl = DTR_CONTROL_ENABLE; - dcb.fDsrSensitivity = FALSE; - dcb.fTXContinueOnXoff = FALSE; - dcb.fOutX = FALSE; - dcb.fInX = FALSE; - dcb.fErrorChar = FALSE; - dcb.fNull = FALSE; - dcb.fRtsControl = RTS_CONTROL_ENABLE; - dcb.fAbortOnError = FALSE; - dcb.XonLim = 10; - dcb.XoffLim = 10; - dcb.ByteSize = 8; - dcb.Parity = NOPARITY; - dcb.StopBits = ONESTOPBIT; - dcb.XonChar = 17; - dcb.XoffChar = 19; -#if 0 - dcb.ErrorChar = 0; - dcb.EofChar = 0; - dcb.EvtChar = 0; -#endif - if (!SetCommState(handle, &dcb)) { - altos_set_last_windows_error(); - CloseHandle(handle); - return INVALID_HANDLE_VALUE; - } - return handle; -} - -PUBLIC struct altos_file * -altos_open(struct altos_device *device) -{ - struct altos_file *file = calloc (1, sizeof (struct altos_file)); - char full_name[64]; - COMMTIMEOUTS timeouts; - int i; - - if (!file) - return NULL; - - strcpy(full_name, "\\\\.\\"); - strcat(full_name, device->path); - - file->handle = INVALID_HANDLE_VALUE; - - for (i = 0; i < 5; i++) { - file->handle = open_serial(full_name); - if (file->handle != INVALID_HANDLE_VALUE) - break; - altos_set_last_windows_error(); - Sleep(100); - } - - if (file->handle == INVALID_HANDLE_VALUE) { - free(file); - return NULL; - } - - /* The FTDI driver doesn't appear to work right unless you open it twice */ - if (device->vendor == 0x0403) { - CloseHandle(file->handle); - file->handle = open_serial(full_name); - if (file->handle == INVALID_HANDLE_VALUE) { - free(file); - return NULL; - } - } - - timeouts.ReadIntervalTimeout = MAXDWORD; - timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; - timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */ - timeouts.WriteTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - SetCommTimeouts(file->handle, &timeouts); - - file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - return file; -} - -PUBLIC void -altos_close(struct altos_file *file) -{ - HANDLE handle = file->handle; - if (handle != INVALID_HANDLE_VALUE) { - HANDLE ov_read = file->ov_read.hEvent; - HANDLE ov_write = file->ov_write.hEvent; - file->handle = INVALID_HANDLE_VALUE; - file->ov_read.hEvent = INVALID_HANDLE_VALUE; - file->ov_write.hEvent = INVALID_HANDLE_VALUE; - PurgeComm(handle, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR); - Sleep(100); - CloseHandle(handle); - file->handle = INVALID_HANDLE_VALUE; - CloseHandle(ov_read); - CloseHandle(ov_write); - } -} - -PUBLIC void -altos_free(struct altos_file *file) -{ - altos_close(file); - free(file); -} - -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) - return ret; - } - file->out_data[file->out_used++] = c; - if (file->out_used == USB_BUF_SIZE) - return altos_flush(file); - return LIBALTOS_SUCCESS; -} - -PUBLIC int -altos_getchar(struct altos_file *file, int timeout) -{ - int ret; - while (file->in_read == file->in_used) { - if (file->handle == INVALID_HANDLE_VALUE) { - altos_set_last_windows_error(); - return LIBALTOS_ERROR; - } - ret = altos_fill(file, timeout); - if (ret) - return ret; - } - return file->in_data[file->in_read++]; -} - -struct altos_bt_list * -altos_bt_list_start(int inquiry_time) -{ - return NULL; -} - -int -altos_bt_list_next(struct altos_bt_list *bt_list, - struct altos_bt_device *device) -{ - return 0; -} - -void -altos_bt_list_finish(struct altos_bt_list *bt_list) -{ - free(bt_list); -} - -void -altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device) -{ - strncpy(device->name, name, sizeof (device->name)); - device->name[sizeof(device->name)-1] = '\0'; - strncpy(device->addr, addr, sizeof (device->addr)); - device->addr[sizeof(device->addr)-1] = '\0'; -} - -struct altos_file * -altos_bt_open(struct altos_bt_device *device) -{ - return NULL; -} - -#endif