2 * Copyright © 2010 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 #define BLUETOOTH_PRODUCT_TELEBT "TeleBT"
30 return LIBALTOS_SUCCESS;
38 static struct altos_error last_error;
41 altos_set_last_error(int code, char *string)
43 last_error.code = code;
44 strncpy(last_error.string, string, sizeof (last_error.string) -1);
45 last_error.string[sizeof(last_error.string)-1] = '\0';
49 altos_get_last_error(struct altos_error *error)
60 /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
62 altos_strndup (const char *s, size_t n)
64 size_t len = strlen (s);
76 #define altos_strndup strndup
87 #define USB_BUF_SIZE 64
96 unsigned char out_data[USB_BUF_SIZE];
98 unsigned char in_data[USB_BUF_SIZE];
104 altos_set_last_posix_error(void)
106 altos_set_last_error(errno, strerror(errno));
109 PUBLIC struct altos_file *
110 altos_open(struct altos_device *device)
112 struct altos_file *file = calloc (sizeof (struct altos_file), 1);
117 altos_set_last_posix_error();
121 // altos_set_last_error(12, "yeah yeah, failed again");
125 file->fd = open(device->path, O_RDWR | O_NOCTTY);
127 altos_set_last_posix_error();
134 file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
135 if (file->out_fd < 0) {
136 altos_set_last_posix_error();
142 ret = tcgetattr(file->fd, &term);
144 altos_set_last_posix_error();
153 cfsetospeed(&term, B9600);
154 cfsetispeed(&term, B9600);
157 term.c_cc[VTIME] = 0;
160 term.c_cc[VTIME] = 1;
162 ret = tcsetattr(file->fd, TCSAFLUSH, &term);
164 altos_set_last_posix_error();
176 altos_close(struct altos_file *file)
178 if (file->fd != -1) {
182 write(file->pipe[1], "\r", 1);
192 altos_free(struct altos_file *file)
199 altos_flush(struct altos_file *file)
201 if (file->out_used && 0) {
203 fwrite(file->out_data, 1, file->out_used, stdout);
206 while (file->out_used) {
212 ret = write (file->fd, file->out_data, file->out_used);
214 ret = write (file->out_fd, file->out_data, file->out_used);
217 altos_set_last_posix_error();
218 return -last_error.code;
221 memmove(file->out_data, file->out_data + ret,
222 file->out_used - ret);
223 file->out_used -= ret;
230 altos_putchar(struct altos_file *file, char c)
234 if (file->out_used == USB_BUF_SIZE) {
235 ret = altos_flush(file);
240 file->out_data[file->out_used++] = c;
242 if (file->out_used == USB_BUF_SIZE)
243 ret = altos_flush(file);
252 altos_fill(struct altos_file *file, int timeout)
261 while (file->in_read == file->in_used) {
263 return LIBALTOS_ERROR;
266 fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
267 fd[1].fd = file->pipe[0];
268 fd[1].events = POLLIN;
269 ret = poll(fd, 2, timeout);
271 altos_set_last_posix_error();
272 return LIBALTOS_ERROR;
275 return LIBALTOS_TIMEOUT;
277 if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
278 return LIBALTOS_ERROR;
279 if (fd[0].revents & POLLIN)
282 ret = read(file->fd, file->in_data, USB_BUF_SIZE);
284 altos_set_last_posix_error();
285 return LIBALTOS_ERROR;
290 if (ret == 0 && timeout > 0)
291 return LIBALTOS_TIMEOUT;
295 if (file->in_used && 0) {
297 fwrite(file->in_data, 1, file->in_used, stdout);
304 altos_getchar(struct altos_file *file, int timeout)
307 while (file->in_read == file->in_used) {
309 return LIBALTOS_ERROR;
310 ret = altos_fill(file, timeout);
314 return file->in_data[file->in_read++];
317 #endif /* POSIX_TTY */
320 * Scan for Altus Metrum devices by looking through /sys
331 #include <bluetooth/bluetooth.h>
332 #include <bluetooth/hci.h>
333 #include <bluetooth/hci_lib.h>
334 #include <bluetooth/rfcomm.h>
337 cc_fullname (char *dir, char *file)
340 int dlen = strlen (dir);
341 int flen = strlen (file);
344 if (dir[dlen-1] != '/')
346 new = malloc (dlen + slen + flen + 1);
357 cc_basename(char *file)
361 b = strrchr(file, '/');
368 load_string(char *dir, char *file)
370 char *full = cc_fullname(dir, file);
376 f = fopen(full, "r");
380 r = fgets(line, sizeof (line), f);
385 if (r[rlen-1] == '\n')
391 load_hex(char *dir, char *file)
397 line = load_string(dir, file);
400 i = strtol(line, &end, 16);
408 load_dec(char *dir, char *file)
414 line = load_string(dir, file);
417 i = strtol(line, &end, 10);
425 dir_filter_tty_colon(const struct dirent *d)
427 return strncmp(d->d_name, "tty:", 4) == 0;
431 dir_filter_tty(const struct dirent *d)
433 return strncmp(d->d_name, "tty", 3) == 0;
436 struct altos_usbdev {
441 int serial; /* AltOS always uses simple integer serial numbers */
452 struct dirent **namelist;
455 char endpoint_base[20];
461 base = cc_basename(sys);
462 num_configs = load_hex(sys, "bNumConfigurations");
463 num_interfaces = load_hex(sys, "bNumInterfaces");
464 for (config = 1; config <= num_configs; config++) {
465 for (interface = 0; interface < num_interfaces; interface++) {
466 sprintf(endpoint_base, "%s:%d.%d",
467 base, config, interface);
468 endpoint_full = cc_fullname(sys, endpoint_base);
471 /* Check for tty:ttyACMx style names
473 ntty = scandir(endpoint_full, &namelist,
474 dir_filter_tty_colon,
478 tty = cc_fullname("/dev", namelist[0]->d_name + 4);
483 /* Check for tty/ttyACMx style names
485 tty_dir = cc_fullname(endpoint_full, "tty");
486 ntty = scandir(tty_dir, &namelist,
491 tty = cc_fullname("/dev", namelist[0]->d_name);
497 /* Check for ttyACMx style names
499 ntty = scandir(endpoint_full, &namelist,
504 tty = cc_fullname("/dev", namelist[0]->d_name);
514 static struct altos_usbdev *
515 usb_scan_device(char *sys)
517 struct altos_usbdev *usbdev;
523 usbdev = calloc(1, sizeof (struct altos_usbdev));
526 usbdev->sys = strdup(sys);
527 usbdev->manufacturer = load_string(sys, "manufacturer");
528 usbdev->product_name = load_string(sys, "product");
529 usbdev->serial = load_dec(sys, "serial");
530 usbdev->idProduct = load_hex(sys, "idProduct");
531 usbdev->idVendor = load_hex(sys, "idVendor");
537 usbdev_free(struct altos_usbdev *usbdev)
540 free(usbdev->manufacturer);
541 free(usbdev->product_name);
542 /* this can get used as a return value */
548 #define USB_DEVICES "/sys/bus/usb/devices"
551 dir_filter_dev(const struct dirent *d)
553 const char *n = d->d_name;
561 if (c == '.' && n != d->d_name + 1)
569 struct altos_usbdev **dev;
575 altos_list_start(void)
578 struct dirent **ents;
580 struct altos_usbdev *dev;
581 struct altos_list *devs;
584 devs = calloc(1, sizeof (struct altos_list));
588 n = scandir (USB_DEVICES, &ents,
593 for (e = 0; e < n; e++) {
594 dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
595 dev = usb_scan_device(dir);
600 devs->dev = realloc(devs->dev,
601 (devs->ndev + 1) * sizeof (struct usbdev *));
603 devs->dev = malloc (sizeof (struct usbdev *));
604 devs->dev[devs->ndev++] = dev;
611 PUBLIC struct altos_list *
612 altos_ftdi_list_start(void)
614 return altos_list_start();
618 altos_list_next(struct altos_list *list, struct altos_device *device)
620 struct altos_usbdev *dev;
621 if (list->current >= list->ndev) {
624 dev = list->dev[list->current];
625 strcpy(device->name, dev->product_name);
626 device->vendor = dev->idVendor;
627 device->product = dev->idProduct;
628 strcpy(device->path, dev->tty);
629 device->serial = dev->serial;
635 altos_list_finish(struct altos_list *usbdevs)
641 for (i = 0; i < usbdevs->ndev; i++)
642 usbdev_free(usbdevs->dev[i]);
646 struct altos_bt_list {
654 #define INQUIRY_MAX_RSP 255
656 struct altos_bt_list *
657 altos_bt_list_start(int inquiry_time)
659 struct altos_bt_list *bt_list;
661 bt_list = calloc(1, sizeof (struct altos_bt_list));
665 bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info));
668 bt_list->dev_id = hci_get_route(NULL);
669 if (bt_list->dev_id < 0)
672 bt_list->sock = hci_open_dev(bt_list->dev_id);
673 if (bt_list->sock < 0)
676 bt_list->num_rsp = hci_inquiry(bt_list->dev_id,
682 if (bt_list->num_rsp < 0)
689 close(bt_list->sock);
700 altos_bt_list_next(struct altos_bt_list *bt_list,
701 struct altos_bt_device *device)
705 if (bt_list->rsp >= bt_list->num_rsp)
708 ii = &bt_list->ii[bt_list->rsp];
709 ba2str(&ii->bdaddr, device->addr);
710 memset(&device->name, '\0', sizeof (device->name));
711 if (hci_read_remote_name(bt_list->sock, &ii->bdaddr,
712 sizeof (device->name),
713 device->name, 0) < 0) {
714 strcpy(device->name, "[unknown]");
721 altos_bt_list_finish(struct altos_bt_list *bt_list)
723 close(bt_list->sock);
729 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
731 strncpy(device->name, name, sizeof (device->name));
732 device->name[sizeof(device->name)-1] = '\0';
733 strncpy(device->addr, addr, sizeof (device->addr));
734 device->addr[sizeof(device->addr)-1] = '\0';
738 altos_bt_open(struct altos_bt_device *device)
740 struct sockaddr_rc addr = { 0 };
742 struct altos_file *file;
744 file = calloc(1, sizeof (struct altos_file));
747 addr.rc_family = AF_BLUETOOTH;
749 str2ba(device->addr, &addr.rc_bdaddr);
751 for (i = 0; i < 5; i++) {
752 file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
754 altos_set_last_posix_error();
758 status = connect(file->fd,
759 (struct sockaddr *)&addr,
761 if (status >= 0 || errno != EBUSY)
767 altos_set_last_posix_error();
775 file->out_fd = dup(file->fd);
790 #include <IOKitLib.h>
791 #include <IOKit/usb/USBspec.h>
792 #include <sys/param.h>
794 #include <CFNumber.h>
801 io_iterator_t iterator;
806 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
808 CFTypeRef entry_as_string;
811 entry_as_string = IORegistryEntrySearchCFProperty (object,
815 kIORegistryIterateRecursively);
816 if (entry_as_string) {
817 got_string = CFStringGetCString(entry_as_string,
819 kCFStringEncodingASCII);
821 CFRelease(entry_as_string);
829 get_number(io_object_t object, CFStringRef entry, int *result)
831 CFTypeRef entry_as_number;
834 entry_as_number = IORegistryEntrySearchCFProperty (object,
838 kIORegistryIterateRecursively);
839 if (entry_as_number) {
840 got_number = CFNumberGetValue(entry_as_number,
849 PUBLIC struct altos_list *
850 altos_list_start(void)
852 struct altos_list *list = calloc (sizeof (struct altos_list), 1);
853 CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
854 io_iterator_t tdIterator;
855 io_object_t tdObject;
859 ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
860 if (ret != kIOReturnSuccess) {
868 PUBLIC struct altos_list *
869 altos_ftdi_list_start(void)
871 struct altos_list *list = altos_list_start();
879 altos_list_next(struct altos_list *list, struct altos_device *device)
882 char serial_string[128];
885 object = IOIteratorNext(list->iterator);
889 if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
890 !get_number (object, CFSTR(kUSBProductID), &device->product))
892 if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
893 get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
894 get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
895 device->serial = atoi(serial_string);
902 altos_list_finish(struct altos_list *list)
904 IOObjectRelease (list->iterator);
908 struct altos_bt_list {
915 #define INQUIRY_MAX_RSP 255
917 struct altos_bt_list *
918 altos_bt_list_start(int inquiry_time)
924 altos_bt_list_next(struct altos_bt_list *bt_list,
925 struct altos_bt_device *device)
931 altos_bt_list_finish(struct altos_bt_list *bt_list)
936 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
938 strncpy(device->name, name, sizeof (device->name));
939 device->name[sizeof(device->name)-1] = '\0';
940 strncpy(device->addr, addr, sizeof (device->addr));
941 device->addr[sizeof(device->addr)-1] = '\0';
945 altos_bt_open(struct altos_bt_device *device)
957 #include <setupapi.h>
965 #define USB_BUF_SIZE 64
969 unsigned char out_data[USB_BUF_SIZE];
971 unsigned char in_data[USB_BUF_SIZE];
982 log_message(char *fmt, ...)
984 static FILE *log = NULL;
988 log = fopen("\\temp\\altos.txt", "w");
992 fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ",
993 time.wYear, time.wMonth, time.wDay,
994 time.wHour, time.wMinute, time.wSecond);
996 vfprintf(log, fmt, a);
1003 _altos_set_last_windows_error(char *file, int line)
1005 DWORD error = GetLastError();
1006 TCHAR message[1024];
1007 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1012 sizeof (message) / sizeof (TCHAR),
1014 if (error != ERROR_SUCCESS)
1015 log_message ("%s:%d %s\n", file, line, message);
1016 altos_set_last_error(error, message);
1019 #define altos_set_last_windows_error() _altos_set_last_windows_error(__FILE__, __LINE__)
1021 PUBLIC struct altos_list *
1022 altos_list_start(void)
1024 struct altos_list *list = calloc(1, sizeof (struct altos_list));
1028 list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
1029 DIGCF_ALLCLASSES|DIGCF_PRESENT);
1030 if (list->dev_info == INVALID_HANDLE_VALUE) {
1031 altos_set_last_windows_error();
1040 PUBLIC struct altos_list *
1041 altos_ftdi_list_start(void)
1043 struct altos_list *list = calloc(1, sizeof (struct altos_list));
1047 list->dev_info = SetupDiGetClassDevs(NULL, "FTDIBUS", NULL,
1048 DIGCF_ALLCLASSES|DIGCF_PRESENT);
1049 if (list->dev_info == INVALID_HANDLE_VALUE) {
1050 altos_set_last_windows_error();
1060 altos_list_next(struct altos_list *list, struct altos_device *device)
1062 SP_DEVINFO_DATA dev_info_data;
1065 char friendlyname[256];
1069 unsigned int vid, pid;
1072 DWORD friendlyname_type;
1073 DWORD friendlyname_len;
1075 dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
1076 while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
1081 dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
1082 DICS_FLAG_GLOBAL, 0, DIREG_DEV,
1084 if (dev_key == INVALID_HANDLE_VALUE) {
1085 altos_set_last_windows_error();
1094 /* Fetch symbolic name for this device and parse out
1095 * the vid/pid/serial info */
1096 symbolic_len = sizeof(symbolic);
1097 result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
1098 symbolic, &symbolic_len);
1100 altos_set_last_windows_error();
1101 RegCloseKey(dev_key);
1104 vid = pid = serial = 0;
1105 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1,
1107 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
1109 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
1113 /* Fetch the com port name */
1114 port_len = sizeof (port);
1115 result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
1117 RegCloseKey(dev_key);
1119 altos_set_last_windows_error();
1123 /* Fetch the device description which is the device name,
1124 * with firmware that has unique USB ids */
1125 friendlyname_len = sizeof (friendlyname);
1126 if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
1130 (BYTE *)friendlyname,
1131 sizeof(friendlyname),
1134 altos_set_last_windows_error();
1137 device->vendor = vid;
1138 device->product = pid;
1139 device->serial = serial;
1140 strcpy(device->name, friendlyname);
1142 strcpy(device->path, (char *) port);
1145 result = GetLastError();
1146 if (result != ERROR_NO_MORE_ITEMS)
1147 altos_set_last_windows_error();
1152 altos_list_finish(struct altos_list *list)
1154 SetupDiDestroyDeviceInfoList(list->dev_info);
1159 altos_queue_read(struct altos_file *file)
1162 if (file->pend_read)
1163 return LIBALTOS_SUCCESS;
1165 if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
1166 if (GetLastError() != ERROR_IO_PENDING) {
1167 altos_set_last_windows_error();
1168 return LIBALTOS_ERROR;
1170 file->pend_read = TRUE;
1172 file->pend_read = FALSE;
1174 file->in_used = got;
1176 return LIBALTOS_SUCCESS;
1180 altos_wait_read(struct altos_file *file, int timeout)
1185 if (!file->pend_read)
1186 return LIBALTOS_SUCCESS;
1191 ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
1194 if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) {
1195 altos_set_last_windows_error();
1196 return LIBALTOS_ERROR;
1198 file->pend_read = FALSE;
1200 file->in_used = got;
1203 return LIBALTOS_TIMEOUT;
1206 altos_set_last_windows_error();
1207 return LIBALTOS_ERROR;
1209 return LIBALTOS_SUCCESS;
1213 altos_fill(struct altos_file *file, int timeout)
1217 if (file->in_read < file->in_used)
1218 return LIBALTOS_SUCCESS;
1220 file->in_read = file->in_used = 0;
1222 ret = altos_queue_read(file);
1225 ret = altos_wait_read(file, timeout);
1229 return LIBALTOS_SUCCESS;
1233 altos_flush(struct altos_file *file)
1236 unsigned char *data = file->out_data;
1237 int used = file->out_used;
1241 if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
1242 if (GetLastError() != ERROR_IO_PENDING) {
1243 altos_set_last_windows_error();
1244 return LIBALTOS_ERROR;
1246 ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
1249 if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) {
1250 altos_set_last_windows_error();
1251 return LIBALTOS_ERROR;
1255 altos_set_last_windows_error();
1256 return LIBALTOS_ERROR;
1263 return LIBALTOS_SUCCESS;
1267 open_serial(char *full_name)
1272 handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
1273 0, NULL, OPEN_EXISTING,
1274 FILE_FLAG_OVERLAPPED, NULL);
1276 if (handle == INVALID_HANDLE_VALUE) {
1277 altos_set_last_windows_error();
1278 return INVALID_HANDLE_VALUE;
1281 if (!GetCommState(handle, &dcb)) {
1282 altos_set_last_windows_error();
1283 CloseHandle(handle);
1284 return INVALID_HANDLE_VALUE;
1286 dcb.BaudRate = CBR_9600;
1288 dcb.fParity = FALSE;
1289 dcb.fOutxCtsFlow = FALSE;
1290 dcb.fOutxDsrFlow = FALSE;
1291 dcb.fDtrControl = DTR_CONTROL_ENABLE;
1292 dcb.fDsrSensitivity = FALSE;
1293 dcb.fTXContinueOnXoff = FALSE;
1296 dcb.fErrorChar = FALSE;
1298 dcb.fRtsControl = RTS_CONTROL_ENABLE;
1299 dcb.fAbortOnError = FALSE;
1303 dcb.Parity = NOPARITY;
1304 dcb.StopBits = ONESTOPBIT;
1312 if (!SetCommState(handle, &dcb)) {
1313 altos_set_last_windows_error();
1314 CloseHandle(handle);
1315 return INVALID_HANDLE_VALUE;
1320 PUBLIC struct altos_file *
1321 altos_open(struct altos_device *device)
1323 struct altos_file *file = calloc (1, sizeof (struct altos_file));
1325 COMMTIMEOUTS timeouts;
1331 strcpy(full_name, "\\\\.\\");
1332 strcat(full_name, device->path);
1334 file->handle = INVALID_HANDLE_VALUE;
1336 for (i = 0; i < 5; i++) {
1337 file->handle = open_serial(full_name);
1338 if (file->handle != INVALID_HANDLE_VALUE)
1340 altos_set_last_windows_error();
1344 if (file->handle == INVALID_HANDLE_VALUE) {
1349 /* The FTDI driver doesn't appear to work right unless you open it twice */
1350 if (device->vendor == 0x0403) {
1351 CloseHandle(file->handle);
1352 file->handle = open_serial(full_name);
1353 if (file->handle == INVALID_HANDLE_VALUE) {
1359 timeouts.ReadIntervalTimeout = MAXDWORD;
1360 timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
1361 timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */
1362 timeouts.WriteTotalTimeoutMultiplier = 0;
1363 timeouts.WriteTotalTimeoutConstant = 0;
1364 SetCommTimeouts(file->handle, &timeouts);
1366 file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1367 file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1373 altos_close(struct altos_file *file)
1375 HANDLE handle = file->handle;
1376 if (handle != INVALID_HANDLE_VALUE) {
1377 HANDLE ov_read = file->ov_read.hEvent;
1378 HANDLE ov_write = file->ov_write.hEvent;
1379 file->handle = INVALID_HANDLE_VALUE;
1380 file->ov_read.hEvent = INVALID_HANDLE_VALUE;
1381 file->ov_write.hEvent = INVALID_HANDLE_VALUE;
1382 PurgeComm(handle, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR);
1384 CloseHandle(handle);
1385 file->handle = INVALID_HANDLE_VALUE;
1386 CloseHandle(ov_read);
1387 CloseHandle(ov_write);
1392 altos_free(struct altos_file *file)
1399 altos_putchar(struct altos_file *file, char c)
1403 if (file->out_used == USB_BUF_SIZE) {
1404 ret = altos_flush(file);
1408 file->out_data[file->out_used++] = c;
1409 if (file->out_used == USB_BUF_SIZE)
1410 return altos_flush(file);
1411 return LIBALTOS_SUCCESS;
1415 altos_getchar(struct altos_file *file, int timeout)
1418 while (file->in_read == file->in_used) {
1419 if (file->handle == INVALID_HANDLE_VALUE) {
1420 altos_set_last_windows_error();
1421 return LIBALTOS_ERROR;
1423 ret = altos_fill(file, timeout);
1427 return file->in_data[file->in_read++];
1430 struct altos_bt_list *
1431 altos_bt_list_start(int inquiry_time)
1437 altos_bt_list_next(struct altos_bt_list *bt_list,
1438 struct altos_bt_device *device)
1444 altos_bt_list_finish(struct altos_bt_list *bt_list)
1450 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
1452 strncpy(device->name, name, sizeof (device->name));
1453 device->name[sizeof(device->name)-1] = '\0';
1454 strncpy(device->addr, addr, sizeof (device->addr));
1455 device->addr[sizeof(device->addr)-1] = '\0';
1459 altos_bt_open(struct altos_bt_device *device)