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]);
649 static int bt_initialized;
651 static int init_bt(void) {
652 if (!bt_initialized) {
654 libbt = dlopen("libbluetooth.so.3", RTLD_LAZY);
656 printf("failed to find bluetooth library\n");
658 return libbt != NULL;
661 #define join(a,b) a ## b
662 #define bt_func(name, ret, fail, formals, actuals) \
663 static ret join(altos_, name) formals { \
664 static ret (*name) formals; \
665 if (!init_bt()) return fail; \
666 name = dlsym(libbt, #name); \
667 if (!name) return fail; \
668 return name actuals; \
671 bt_func(ba2str, int, -1, (const bdaddr_t *ba, char *str), (ba, str))
672 #define ba2str altos_ba2str
674 bt_func(str2ba, int, -1, (const char *str, bdaddr_t *ba), (str, ba))
675 #define str2ba altos_str2ba
677 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))
678 #define hci_read_remote_name altos_hci_read_remote_name
680 bt_func(hci_open_dev, int, -1, (int dev_id), (dev_id))
681 #define hci_open_dev altos_hci_open_dev
683 bt_func(hci_get_route, int, -1, (bdaddr_t *bdaddr), (bdaddr))
684 #define hci_get_route altos_hci_get_route
686 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))
687 #define hci_inquiry altos_hci_inquiry
689 struct altos_bt_list {
697 #define INQUIRY_MAX_RSP 255
699 struct altos_bt_list *
700 altos_bt_list_start(int inquiry_time)
702 struct altos_bt_list *bt_list;
704 bt_list = calloc(1, sizeof (struct altos_bt_list));
708 bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info));
711 bt_list->dev_id = hci_get_route(NULL);
712 if (bt_list->dev_id < 0)
715 bt_list->sock = hci_open_dev(bt_list->dev_id);
716 if (bt_list->sock < 0)
719 bt_list->num_rsp = hci_inquiry(bt_list->dev_id,
725 if (bt_list->num_rsp < 0)
732 close(bt_list->sock);
743 altos_bt_list_next(struct altos_bt_list *bt_list,
744 struct altos_bt_device *device)
748 if (bt_list->rsp >= bt_list->num_rsp)
751 ii = &bt_list->ii[bt_list->rsp];
752 if (ba2str(&ii->bdaddr, device->addr) < 0)
754 memset(&device->name, '\0', sizeof (device->name));
755 if (hci_read_remote_name(bt_list->sock, &ii->bdaddr,
756 sizeof (device->name),
757 device->name, 0) < 0) {
758 strcpy(device->name, "[unknown]");
765 altos_bt_list_finish(struct altos_bt_list *bt_list)
767 close(bt_list->sock);
773 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
775 strncpy(device->name, name, sizeof (device->name));
776 device->name[sizeof(device->name)-1] = '\0';
777 strncpy(device->addr, addr, sizeof (device->addr));
778 device->addr[sizeof(device->addr)-1] = '\0';
782 altos_bt_open(struct altos_bt_device *device)
784 struct sockaddr_rc addr = { 0 };
786 struct altos_file *file;
788 file = calloc(1, sizeof (struct altos_file));
791 altos_set_last_posix_error();
794 addr.rc_family = AF_BLUETOOTH;
796 if (str2ba(device->addr, &addr.rc_bdaddr) < 0) {
797 altos_set_last_posix_error();
801 for (i = 0; i < 5; i++) {
802 file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
804 altos_set_last_posix_error();
808 status = connect(file->fd,
809 (struct sockaddr *)&addr,
811 if (status >= 0 || errno != EBUSY)
817 altos_set_last_posix_error();
825 file->out_fd = dup(file->fd);
840 #include <IOKitLib.h>
841 #include <IOKit/usb/USBspec.h>
842 #include <sys/param.h>
844 #include <CFNumber.h>
851 io_iterator_t iterator;
856 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
858 CFTypeRef entry_as_string;
861 entry_as_string = IORegistryEntrySearchCFProperty (object,
865 kIORegistryIterateRecursively);
866 if (entry_as_string) {
867 got_string = CFStringGetCString(entry_as_string,
869 kCFStringEncodingASCII);
871 CFRelease(entry_as_string);
879 get_number(io_object_t object, CFStringRef entry, int *result)
881 CFTypeRef entry_as_number;
884 entry_as_number = IORegistryEntrySearchCFProperty (object,
888 kIORegistryIterateRecursively);
889 if (entry_as_number) {
890 got_number = CFNumberGetValue(entry_as_number,
899 PUBLIC struct altos_list *
900 altos_list_start(void)
902 struct altos_list *list = calloc (sizeof (struct altos_list), 1);
903 CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
904 io_iterator_t tdIterator;
905 io_object_t tdObject;
909 ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
910 if (ret != kIOReturnSuccess) {
918 PUBLIC struct altos_list *
919 altos_ftdi_list_start(void)
921 struct altos_list *list = altos_list_start();
929 altos_list_next(struct altos_list *list, struct altos_device *device)
932 char serial_string[128];
935 object = IOIteratorNext(list->iterator);
939 if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
940 !get_number (object, CFSTR(kUSBProductID), &device->product))
942 if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
943 get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
944 get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
945 device->serial = atoi(serial_string);
952 altos_list_finish(struct altos_list *list)
954 IOObjectRelease (list->iterator);
958 struct altos_bt_list {
965 #define INQUIRY_MAX_RSP 255
967 struct altos_bt_list *
968 altos_bt_list_start(int inquiry_time)
974 altos_bt_list_next(struct altos_bt_list *bt_list,
975 struct altos_bt_device *device)
981 altos_bt_list_finish(struct altos_bt_list *bt_list)
986 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
988 strncpy(device->name, name, sizeof (device->name));
989 device->name[sizeof(device->name)-1] = '\0';
990 strncpy(device->addr, addr, sizeof (device->addr));
991 device->addr[sizeof(device->addr)-1] = '\0';
995 altos_bt_open(struct altos_bt_device *device)
1006 #include <windows.h>
1007 #include <setupapi.h>
1015 #define USB_BUF_SIZE 64
1019 unsigned char out_data[USB_BUF_SIZE];
1021 unsigned char in_data[USB_BUF_SIZE];
1026 OVERLAPPED ov_write;
1032 log_message(char *fmt, ...)
1034 static FILE *log = NULL;
1038 log = fopen("\\temp\\altos.txt", "w");
1041 GetLocalTime(&time);
1042 fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ",
1043 time.wYear, time.wMonth, time.wDay,
1044 time.wHour, time.wMinute, time.wSecond);
1046 vfprintf(log, fmt, a);
1053 _altos_set_last_windows_error(char *file, int line)
1055 DWORD error = GetLastError();
1056 TCHAR message[1024];
1057 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1062 sizeof (message) / sizeof (TCHAR),
1064 if (error != ERROR_SUCCESS)
1065 log_message ("%s:%d %s\n", file, line, message);
1066 altos_set_last_error(error, message);
1069 #define altos_set_last_windows_error() _altos_set_last_windows_error(__FILE__, __LINE__)
1071 PUBLIC struct altos_list *
1072 altos_list_start(void)
1074 struct altos_list *list = calloc(1, sizeof (struct altos_list));
1078 list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
1079 DIGCF_ALLCLASSES|DIGCF_PRESENT);
1080 if (list->dev_info == INVALID_HANDLE_VALUE) {
1081 altos_set_last_windows_error();
1090 PUBLIC struct altos_list *
1091 altos_ftdi_list_start(void)
1093 struct altos_list *list = calloc(1, sizeof (struct altos_list));
1097 list->dev_info = SetupDiGetClassDevs(NULL, "FTDIBUS", NULL,
1098 DIGCF_ALLCLASSES|DIGCF_PRESENT);
1099 if (list->dev_info == INVALID_HANDLE_VALUE) {
1100 altos_set_last_windows_error();
1110 altos_list_next(struct altos_list *list, struct altos_device *device)
1112 SP_DEVINFO_DATA dev_info_data;
1115 char friendlyname[256];
1119 unsigned int vid, pid;
1122 DWORD friendlyname_type;
1123 DWORD friendlyname_len;
1124 char instanceid[1024];
1125 DWORD instanceid_len;
1127 dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
1128 while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
1133 dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
1134 DICS_FLAG_GLOBAL, 0, DIREG_DEV,
1136 if (dev_key == INVALID_HANDLE_VALUE) {
1137 altos_set_last_windows_error();
1146 vid = pid = serial = 0;
1147 /* Fetch symbolic name for this device and parse out
1148 * the vid/pid/serial info */
1149 symbolic_len = sizeof(symbolic);
1150 result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
1151 symbolic, &symbolic_len);
1153 altos_set_last_windows_error();
1155 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1,
1157 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
1159 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
1162 if (vid == 0 || pid == 0 || serial == 0) {
1163 if (SetupDiGetDeviceInstanceId(list->dev_info,
1166 sizeof (instanceid),
1168 sscanf((char *) instanceid + sizeof("USB\\VID_") - 1,
1170 sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_") - 1,
1172 sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_XXXX\\") - 1,
1175 altos_set_last_windows_error();
1178 if (vid == 0 || pid == 0 || serial == 0) {
1179 RegCloseKey(dev_key);
1184 /* Fetch the com port name */
1185 port_len = sizeof (port);
1186 result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
1188 RegCloseKey(dev_key);
1190 altos_set_last_windows_error();
1194 /* Fetch the device description which is the device name,
1195 * with firmware that has unique USB ids */
1196 friendlyname_len = sizeof (friendlyname);
1197 if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
1201 (BYTE *)friendlyname,
1202 sizeof(friendlyname),
1205 altos_set_last_windows_error();
1208 device->vendor = vid;
1209 device->product = pid;
1210 device->serial = serial;
1211 strcpy(device->name, friendlyname);
1213 strcpy(device->path, (char *) port);
1216 result = GetLastError();
1217 if (result != ERROR_NO_MORE_ITEMS)
1218 altos_set_last_windows_error();
1223 altos_list_finish(struct altos_list *list)
1225 SetupDiDestroyDeviceInfoList(list->dev_info);
1230 altos_queue_read(struct altos_file *file)
1233 if (file->pend_read)
1234 return LIBALTOS_SUCCESS;
1236 if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
1237 if (GetLastError() != ERROR_IO_PENDING) {
1238 altos_set_last_windows_error();
1239 return LIBALTOS_ERROR;
1241 file->pend_read = TRUE;
1243 file->pend_read = FALSE;
1245 file->in_used = got;
1247 return LIBALTOS_SUCCESS;
1251 altos_wait_read(struct altos_file *file, int timeout)
1256 if (!file->pend_read)
1257 return LIBALTOS_SUCCESS;
1262 ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
1265 if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) {
1266 altos_set_last_windows_error();
1267 return LIBALTOS_ERROR;
1269 file->pend_read = FALSE;
1271 file->in_used = got;
1274 return LIBALTOS_TIMEOUT;
1277 altos_set_last_windows_error();
1278 return LIBALTOS_ERROR;
1280 return LIBALTOS_SUCCESS;
1284 altos_fill(struct altos_file *file, int timeout)
1288 if (file->in_read < file->in_used)
1289 return LIBALTOS_SUCCESS;
1291 file->in_read = file->in_used = 0;
1293 ret = altos_queue_read(file);
1296 ret = altos_wait_read(file, timeout);
1300 return LIBALTOS_SUCCESS;
1304 altos_flush(struct altos_file *file)
1307 unsigned char *data = file->out_data;
1308 int used = file->out_used;
1312 if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
1313 if (GetLastError() != ERROR_IO_PENDING) {
1314 altos_set_last_windows_error();
1315 return LIBALTOS_ERROR;
1317 ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
1320 if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) {
1321 altos_set_last_windows_error();
1322 return LIBALTOS_ERROR;
1326 altos_set_last_windows_error();
1327 return LIBALTOS_ERROR;
1334 return LIBALTOS_SUCCESS;
1338 open_serial(char *full_name)
1343 handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
1344 0, NULL, OPEN_EXISTING,
1345 FILE_FLAG_OVERLAPPED, NULL);
1347 if (handle == INVALID_HANDLE_VALUE) {
1348 altos_set_last_windows_error();
1349 return INVALID_HANDLE_VALUE;
1352 if (!GetCommState(handle, &dcb)) {
1353 altos_set_last_windows_error();
1354 CloseHandle(handle);
1355 return INVALID_HANDLE_VALUE;
1357 dcb.BaudRate = CBR_9600;
1359 dcb.fParity = FALSE;
1360 dcb.fOutxCtsFlow = FALSE;
1361 dcb.fOutxDsrFlow = FALSE;
1362 dcb.fDtrControl = DTR_CONTROL_ENABLE;
1363 dcb.fDsrSensitivity = FALSE;
1364 dcb.fTXContinueOnXoff = FALSE;
1367 dcb.fErrorChar = FALSE;
1369 dcb.fRtsControl = RTS_CONTROL_ENABLE;
1370 dcb.fAbortOnError = FALSE;
1374 dcb.Parity = NOPARITY;
1375 dcb.StopBits = ONESTOPBIT;
1383 if (!SetCommState(handle, &dcb)) {
1384 altos_set_last_windows_error();
1385 CloseHandle(handle);
1386 return INVALID_HANDLE_VALUE;
1391 PUBLIC struct altos_file *
1392 altos_open(struct altos_device *device)
1394 struct altos_file *file = calloc (1, sizeof (struct altos_file));
1396 COMMTIMEOUTS timeouts;
1402 strcpy(full_name, "\\\\.\\");
1403 strcat(full_name, device->path);
1405 file->handle = INVALID_HANDLE_VALUE;
1407 for (i = 0; i < 5; i++) {
1408 file->handle = open_serial(full_name);
1409 if (file->handle != INVALID_HANDLE_VALUE)
1411 altos_set_last_windows_error();
1415 if (file->handle == INVALID_HANDLE_VALUE) {
1420 /* The FTDI driver doesn't appear to work right unless you open it twice */
1421 if (device->vendor == 0x0403) {
1422 CloseHandle(file->handle);
1423 file->handle = open_serial(full_name);
1424 if (file->handle == INVALID_HANDLE_VALUE) {
1430 timeouts.ReadIntervalTimeout = MAXDWORD;
1431 timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
1432 timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */
1433 timeouts.WriteTotalTimeoutMultiplier = 0;
1434 timeouts.WriteTotalTimeoutConstant = 0;
1435 SetCommTimeouts(file->handle, &timeouts);
1437 file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1438 file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1444 altos_close(struct altos_file *file)
1446 HANDLE handle = file->handle;
1447 if (handle != INVALID_HANDLE_VALUE) {
1448 HANDLE ov_read = file->ov_read.hEvent;
1449 HANDLE ov_write = file->ov_write.hEvent;
1450 file->handle = INVALID_HANDLE_VALUE;
1451 file->ov_read.hEvent = INVALID_HANDLE_VALUE;
1452 file->ov_write.hEvent = INVALID_HANDLE_VALUE;
1453 PurgeComm(handle, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR);
1455 CloseHandle(handle);
1456 file->handle = INVALID_HANDLE_VALUE;
1457 CloseHandle(ov_read);
1458 CloseHandle(ov_write);
1463 altos_free(struct altos_file *file)
1470 altos_putchar(struct altos_file *file, char c)
1474 if (file->out_used == USB_BUF_SIZE) {
1475 ret = altos_flush(file);
1479 file->out_data[file->out_used++] = c;
1480 if (file->out_used == USB_BUF_SIZE)
1481 return altos_flush(file);
1482 return LIBALTOS_SUCCESS;
1486 altos_getchar(struct altos_file *file, int timeout)
1489 while (file->in_read == file->in_used) {
1490 if (file->handle == INVALID_HANDLE_VALUE) {
1491 altos_set_last_windows_error();
1492 return LIBALTOS_ERROR;
1494 ret = altos_fill(file, timeout);
1498 return file->in_data[file->in_read++];
1501 struct altos_bt_list *
1502 altos_bt_list_start(int inquiry_time)
1508 altos_bt_list_next(struct altos_bt_list *bt_list,
1509 struct altos_bt_device *device)
1515 altos_bt_list_finish(struct altos_bt_list *bt_list)
1521 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
1523 strncpy(device->name, name, sizeof (device->name));
1524 device->name[sizeof(device->name)-1] = '\0';
1525 strncpy(device->addr, addr, sizeof (device->addr));
1526 device->addr[sizeof(device->addr)-1] = '\0';
1530 altos_bt_open(struct altos_bt_device *device)