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
88 #define USB_BUF_SIZE 64
97 unsigned char out_data[USB_BUF_SIZE];
99 unsigned char in_data[USB_BUF_SIZE];
105 altos_set_last_posix_error(void)
107 altos_set_last_error(errno, strerror(errno));
110 PUBLIC struct altos_file *
111 altos_open(struct altos_device *device)
113 struct altos_file *file = calloc (sizeof (struct altos_file), 1);
118 altos_set_last_posix_error();
122 // altos_set_last_error(12, "yeah yeah, failed again");
126 file->fd = open(device->path, O_RDWR | O_NOCTTY);
128 altos_set_last_posix_error();
135 file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
136 if (file->out_fd < 0) {
137 altos_set_last_posix_error();
143 ret = tcgetattr(file->fd, &term);
145 altos_set_last_posix_error();
154 cfsetospeed(&term, B9600);
155 cfsetispeed(&term, B9600);
158 term.c_cc[VTIME] = 0;
161 term.c_cc[VTIME] = 1;
163 ret = tcsetattr(file->fd, TCSAFLUSH, &term);
165 altos_set_last_posix_error();
177 altos_close(struct altos_file *file)
179 if (file->fd != -1) {
183 write(file->pipe[1], "\r", 1);
193 altos_free(struct altos_file *file)
200 altos_flush(struct altos_file *file)
202 if (file->out_used && 0) {
204 fwrite(file->out_data, 1, file->out_used, stdout);
207 while (file->out_used) {
213 ret = write (file->fd, file->out_data, file->out_used);
215 ret = write (file->out_fd, file->out_data, file->out_used);
218 altos_set_last_posix_error();
219 return -last_error.code;
222 memmove(file->out_data, file->out_data + ret,
223 file->out_used - ret);
224 file->out_used -= ret;
231 altos_putchar(struct altos_file *file, char c)
235 if (file->out_used == USB_BUF_SIZE) {
236 ret = altos_flush(file);
241 file->out_data[file->out_used++] = c;
243 if (file->out_used == USB_BUF_SIZE)
244 ret = altos_flush(file);
253 altos_fill(struct altos_file *file, int timeout)
262 while (file->in_read == file->in_used) {
264 return LIBALTOS_ERROR;
267 fd[0].events = POLLIN|POLLERR|POLLHUP|POLLNVAL;
268 fd[1].fd = file->pipe[0];
269 fd[1].events = POLLIN;
270 ret = poll(fd, 2, timeout);
272 altos_set_last_posix_error();
273 return LIBALTOS_ERROR;
276 return LIBALTOS_TIMEOUT;
278 if (fd[0].revents & (POLLHUP|POLLERR|POLLNVAL))
279 return LIBALTOS_ERROR;
280 if (fd[0].revents & POLLIN)
283 ret = read(file->fd, file->in_data, USB_BUF_SIZE);
285 altos_set_last_posix_error();
286 return LIBALTOS_ERROR;
291 if (ret == 0 && timeout > 0)
292 return LIBALTOS_TIMEOUT;
296 if (file->in_used && 0) {
298 fwrite(file->in_data, 1, file->in_used, stdout);
305 altos_getchar(struct altos_file *file, int timeout)
308 while (file->in_read == file->in_used) {
310 return LIBALTOS_ERROR;
311 ret = altos_fill(file, timeout);
315 return file->in_data[file->in_read++];
318 #endif /* POSIX_TTY */
321 * Scan for Altus Metrum devices by looking through /sys
332 #include <bluetooth/bluetooth.h>
333 #include <bluetooth/hci.h>
334 #include <bluetooth/hci_lib.h>
335 #include <bluetooth/rfcomm.h>
338 cc_fullname (char *dir, char *file)
341 int dlen = strlen (dir);
342 int flen = strlen (file);
345 if (dir[dlen-1] != '/')
347 new = malloc (dlen + slen + flen + 1);
358 cc_basename(char *file)
362 b = strrchr(file, '/');
369 load_string(char *dir, char *file)
371 char *full = cc_fullname(dir, file);
377 f = fopen(full, "r");
381 r = fgets(line, sizeof (line), f);
386 if (r[rlen-1] == '\n')
392 load_hex(char *dir, char *file)
398 line = load_string(dir, file);
401 i = strtol(line, &end, 16);
409 load_dec(char *dir, char *file)
415 line = load_string(dir, file);
418 i = strtol(line, &end, 10);
426 dir_filter_tty_colon(const struct dirent *d)
428 return strncmp(d->d_name, "tty:", 4) == 0;
432 dir_filter_tty(const struct dirent *d)
434 return strncmp(d->d_name, "tty", 3) == 0;
437 struct altos_usbdev {
442 int serial; /* AltOS always uses simple integer serial numbers */
453 struct dirent **namelist;
456 char endpoint_base[20];
462 base = cc_basename(sys);
463 num_configs = load_hex(sys, "bNumConfigurations");
464 num_interfaces = load_hex(sys, "bNumInterfaces");
465 for (config = 1; config <= num_configs; config++) {
466 for (interface = 0; interface < num_interfaces; interface++) {
467 sprintf(endpoint_base, "%s:%d.%d",
468 base, config, interface);
469 endpoint_full = cc_fullname(sys, endpoint_base);
472 /* Check for tty:ttyACMx style names
474 ntty = scandir(endpoint_full, &namelist,
475 dir_filter_tty_colon,
479 tty = cc_fullname("/dev", namelist[0]->d_name + 4);
484 /* Check for tty/ttyACMx style names
486 tty_dir = cc_fullname(endpoint_full, "tty");
487 ntty = scandir(tty_dir, &namelist,
492 tty = cc_fullname("/dev", namelist[0]->d_name);
498 /* Check for ttyACMx style names
500 ntty = scandir(endpoint_full, &namelist,
505 tty = cc_fullname("/dev", namelist[0]->d_name);
515 static struct altos_usbdev *
516 usb_scan_device(char *sys)
518 struct altos_usbdev *usbdev;
524 usbdev = calloc(1, sizeof (struct altos_usbdev));
527 usbdev->sys = strdup(sys);
528 usbdev->manufacturer = load_string(sys, "manufacturer");
529 usbdev->product_name = load_string(sys, "product");
530 usbdev->serial = load_dec(sys, "serial");
531 usbdev->idProduct = load_hex(sys, "idProduct");
532 usbdev->idVendor = load_hex(sys, "idVendor");
538 usbdev_free(struct altos_usbdev *usbdev)
541 free(usbdev->manufacturer);
542 free(usbdev->product_name);
543 /* this can get used as a return value */
549 #define USB_DEVICES "/sys/bus/usb/devices"
552 dir_filter_dev(const struct dirent *d)
554 const char *n = d->d_name;
562 if (c == '.' && n != d->d_name + 1)
570 struct altos_usbdev **dev;
576 altos_list_start(void)
579 struct dirent **ents;
581 struct altos_usbdev *dev;
582 struct altos_list *devs;
585 devs = calloc(1, sizeof (struct altos_list));
589 n = scandir (USB_DEVICES, &ents,
594 for (e = 0; e < n; e++) {
595 dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
596 dev = usb_scan_device(dir);
601 devs->dev = realloc(devs->dev,
602 (devs->ndev + 1) * sizeof (struct usbdev *));
604 devs->dev = malloc (sizeof (struct usbdev *));
605 devs->dev[devs->ndev++] = dev;
612 PUBLIC struct altos_list *
613 altos_ftdi_list_start(void)
615 return altos_list_start();
619 altos_list_next(struct altos_list *list, struct altos_device *device)
621 struct altos_usbdev *dev;
622 if (list->current >= list->ndev) {
625 dev = list->dev[list->current];
626 strcpy(device->name, dev->product_name);
627 device->vendor = dev->idVendor;
628 device->product = dev->idProduct;
629 strcpy(device->path, dev->tty);
630 device->serial = dev->serial;
636 altos_list_finish(struct altos_list *usbdevs)
642 for (i = 0; i < usbdevs->ndev; i++)
643 usbdev_free(usbdevs->dev[i]);
650 static int bt_initialized;
652 static int init_bt(void) {
653 if (!bt_initialized) {
655 libbt = dlopen("libbluetooth.so.3", RTLD_LAZY);
657 printf("failed to find bluetooth library\n");
659 return libbt != NULL;
662 #define join(a,b) a ## b
663 #define bt_func(name, ret, fail, formals, actuals) \
664 static ret join(altos_, name) formals { \
665 static ret (*name) formals; \
666 if (!init_bt()) return fail; \
667 name = dlsym(libbt, #name); \
668 if (!name) return fail; \
669 return name actuals; \
672 bt_func(ba2str, int, -1, (const bdaddr_t *ba, char *str), (ba, str))
673 #define ba2str altos_ba2str
675 bt_func(str2ba, int, -1, (const char *str, bdaddr_t *ba), (str, ba))
676 #define str2ba altos_str2ba
678 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))
679 #define hci_read_remote_name altos_hci_read_remote_name
681 bt_func(hci_open_dev, int, -1, (int dev_id), (dev_id))
682 #define hci_open_dev altos_hci_open_dev
684 bt_func(hci_get_route, int, -1, (bdaddr_t *bdaddr), (bdaddr))
685 #define hci_get_route altos_hci_get_route
687 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))
688 #define hci_inquiry altos_hci_inquiry
690 struct altos_bt_list {
698 #define INQUIRY_MAX_RSP 255
700 struct altos_bt_list *
701 altos_bt_list_start(int inquiry_time)
703 struct altos_bt_list *bt_list;
705 bt_list = calloc(1, sizeof (struct altos_bt_list));
709 bt_list->ii = calloc(INQUIRY_MAX_RSP, sizeof (inquiry_info));
712 bt_list->dev_id = hci_get_route(NULL);
713 if (bt_list->dev_id < 0)
716 bt_list->sock = hci_open_dev(bt_list->dev_id);
717 if (bt_list->sock < 0)
720 bt_list->num_rsp = hci_inquiry(bt_list->dev_id,
726 if (bt_list->num_rsp < 0)
733 close(bt_list->sock);
744 altos_bt_list_next(struct altos_bt_list *bt_list,
745 struct altos_bt_device *device)
749 if (bt_list->rsp >= bt_list->num_rsp)
752 ii = &bt_list->ii[bt_list->rsp];
753 if (ba2str(&ii->bdaddr, device->addr) < 0)
755 memset(&device->name, '\0', sizeof (device->name));
756 if (hci_read_remote_name(bt_list->sock, &ii->bdaddr,
757 sizeof (device->name),
758 device->name, 0) < 0) {
759 strcpy(device->name, "[unknown]");
766 altos_bt_list_finish(struct altos_bt_list *bt_list)
768 close(bt_list->sock);
774 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
776 strncpy(device->name, name, sizeof (device->name));
777 device->name[sizeof(device->name)-1] = '\0';
778 strncpy(device->addr, addr, sizeof (device->addr));
779 device->addr[sizeof(device->addr)-1] = '\0';
783 altos_bt_open(struct altos_bt_device *device)
785 struct sockaddr_rc addr = { 0 };
787 struct altos_file *file;
789 file = calloc(1, sizeof (struct altos_file));
792 altos_set_last_posix_error();
795 addr.rc_family = AF_BLUETOOTH;
797 if (str2ba(device->addr, &addr.rc_bdaddr) < 0) {
798 altos_set_last_posix_error();
802 for (i = 0; i < 5; i++) {
803 file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
805 altos_set_last_posix_error();
809 status = connect(file->fd,
810 (struct sockaddr *)&addr,
812 if (status >= 0 || errno != EBUSY)
818 altos_set_last_posix_error();
826 file->out_fd = dup(file->fd);
841 #include <IOKitLib.h>
842 #include <IOKit/usb/USBspec.h>
843 #include <sys/param.h>
845 #include <CFNumber.h>
852 io_iterator_t iterator;
857 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
859 CFTypeRef entry_as_string;
862 entry_as_string = IORegistryEntrySearchCFProperty (object,
866 kIORegistryIterateRecursively);
867 if (entry_as_string) {
868 got_string = CFStringGetCString(entry_as_string,
870 kCFStringEncodingASCII);
872 CFRelease(entry_as_string);
880 get_number(io_object_t object, CFStringRef entry, int *result)
882 CFTypeRef entry_as_number;
885 entry_as_number = IORegistryEntrySearchCFProperty (object,
889 kIORegistryIterateRecursively);
890 if (entry_as_number) {
891 got_number = CFNumberGetValue(entry_as_number,
900 PUBLIC struct altos_list *
901 altos_list_start(void)
903 struct altos_list *list = calloc (sizeof (struct altos_list), 1);
904 CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
905 io_iterator_t tdIterator;
906 io_object_t tdObject;
910 ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
911 if (ret != kIOReturnSuccess) {
919 PUBLIC struct altos_list *
920 altos_ftdi_list_start(void)
922 struct altos_list *list = altos_list_start();
930 altos_list_next(struct altos_list *list, struct altos_device *device)
933 char serial_string[128];
936 object = IOIteratorNext(list->iterator);
940 if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
941 !get_number (object, CFSTR(kUSBProductID), &device->product))
943 if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
944 get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
945 get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
946 device->serial = atoi(serial_string);
953 altos_list_finish(struct altos_list *list)
955 IOObjectRelease (list->iterator);
959 struct altos_bt_list {
966 #define INQUIRY_MAX_RSP 255
968 struct altos_bt_list *
969 altos_bt_list_start(int inquiry_time)
975 altos_bt_list_next(struct altos_bt_list *bt_list,
976 struct altos_bt_device *device)
982 altos_bt_list_finish(struct altos_bt_list *bt_list)
987 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
989 strncpy(device->name, name, sizeof (device->name));
990 device->name[sizeof(device->name)-1] = '\0';
991 strncpy(device->addr, addr, sizeof (device->addr));
992 device->addr[sizeof(device->addr)-1] = '\0';
996 altos_bt_open(struct altos_bt_device *device)
1007 #include <windows.h>
1008 #include <setupapi.h>
1016 #define USB_BUF_SIZE 64
1020 unsigned char out_data[USB_BUF_SIZE];
1022 unsigned char in_data[USB_BUF_SIZE];
1027 OVERLAPPED ov_write;
1033 log_message(char *fmt, ...)
1035 static FILE *log = NULL;
1039 log = fopen("\\temp\\altos.txt", "w");
1042 GetLocalTime(&time);
1043 fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ",
1044 time.wYear, time.wMonth, time.wDay,
1045 time.wHour, time.wMinute, time.wSecond);
1047 vfprintf(log, fmt, a);
1054 _altos_set_last_windows_error(char *file, int line)
1056 DWORD error = GetLastError();
1057 TCHAR message[1024];
1058 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1063 sizeof (message) / sizeof (TCHAR),
1065 if (error != ERROR_SUCCESS)
1066 log_message ("%s:%d %s\n", file, line, message);
1067 altos_set_last_error(error, message);
1070 #define altos_set_last_windows_error() _altos_set_last_windows_error(__FILE__, __LINE__)
1072 PUBLIC struct altos_list *
1073 altos_list_start(void)
1075 struct altos_list *list = calloc(1, sizeof (struct altos_list));
1079 list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
1080 DIGCF_ALLCLASSES|DIGCF_PRESENT);
1081 if (list->dev_info == INVALID_HANDLE_VALUE) {
1082 altos_set_last_windows_error();
1091 PUBLIC struct altos_list *
1092 altos_ftdi_list_start(void)
1094 struct altos_list *list = calloc(1, sizeof (struct altos_list));
1098 list->dev_info = SetupDiGetClassDevs(NULL, "FTDIBUS", NULL,
1099 DIGCF_ALLCLASSES|DIGCF_PRESENT);
1100 if (list->dev_info == INVALID_HANDLE_VALUE) {
1101 altos_set_last_windows_error();
1111 altos_list_next(struct altos_list *list, struct altos_device *device)
1113 SP_DEVINFO_DATA dev_info_data;
1116 char friendlyname[256];
1120 unsigned int vid, pid;
1123 DWORD friendlyname_type;
1124 DWORD friendlyname_len;
1125 char instanceid[1024];
1126 DWORD instanceid_len;
1128 dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
1129 while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
1134 dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
1135 DICS_FLAG_GLOBAL, 0, DIREG_DEV,
1137 if (dev_key == INVALID_HANDLE_VALUE) {
1138 altos_set_last_windows_error();
1147 vid = pid = serial = 0;
1148 /* Fetch symbolic name for this device and parse out
1149 * the vid/pid/serial info */
1150 symbolic_len = sizeof(symbolic);
1151 result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
1152 symbolic, &symbolic_len);
1154 altos_set_last_windows_error();
1156 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1,
1158 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
1160 sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
1163 if (vid == 0 || pid == 0 || serial == 0) {
1164 if (SetupDiGetDeviceInstanceId(list->dev_info,
1167 sizeof (instanceid),
1169 sscanf((char *) instanceid + sizeof("USB\\VID_") - 1,
1171 sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_") - 1,
1173 sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_XXXX\\") - 1,
1176 altos_set_last_windows_error();
1179 if (vid == 0 || pid == 0 || serial == 0) {
1180 RegCloseKey(dev_key);
1185 /* Fetch the com port name */
1186 port_len = sizeof (port);
1187 result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
1189 RegCloseKey(dev_key);
1191 altos_set_last_windows_error();
1195 /* Fetch the device description which is the device name,
1196 * with firmware that has unique USB ids */
1197 friendlyname_len = sizeof (friendlyname);
1198 if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
1202 (BYTE *)friendlyname,
1203 sizeof(friendlyname),
1206 altos_set_last_windows_error();
1209 device->vendor = vid;
1210 device->product = pid;
1211 device->serial = serial;
1212 strcpy(device->name, friendlyname);
1214 strcpy(device->path, (char *) port);
1217 result = GetLastError();
1218 if (result != ERROR_NO_MORE_ITEMS)
1219 altos_set_last_windows_error();
1224 altos_list_finish(struct altos_list *list)
1226 SetupDiDestroyDeviceInfoList(list->dev_info);
1231 altos_queue_read(struct altos_file *file)
1234 if (file->pend_read)
1235 return LIBALTOS_SUCCESS;
1237 if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, &file->ov_read)) {
1238 if (GetLastError() != ERROR_IO_PENDING) {
1239 altos_set_last_windows_error();
1240 return LIBALTOS_ERROR;
1242 file->pend_read = TRUE;
1244 file->pend_read = FALSE;
1246 file->in_used = got;
1248 return LIBALTOS_SUCCESS;
1252 altos_wait_read(struct altos_file *file, int timeout)
1257 if (!file->pend_read)
1258 return LIBALTOS_SUCCESS;
1263 ret = WaitForSingleObject(file->ov_read.hEvent, timeout);
1266 if (!GetOverlappedResult(file->handle, &file->ov_read, &got, FALSE)) {
1267 altos_set_last_windows_error();
1268 return LIBALTOS_ERROR;
1270 file->pend_read = FALSE;
1272 file->in_used = got;
1275 return LIBALTOS_TIMEOUT;
1278 altos_set_last_windows_error();
1279 return LIBALTOS_ERROR;
1281 return LIBALTOS_SUCCESS;
1285 altos_fill(struct altos_file *file, int timeout)
1289 if (file->in_read < file->in_used)
1290 return LIBALTOS_SUCCESS;
1292 file->in_read = file->in_used = 0;
1294 ret = altos_queue_read(file);
1297 ret = altos_wait_read(file, timeout);
1301 return LIBALTOS_SUCCESS;
1305 altos_flush(struct altos_file *file)
1308 unsigned char *data = file->out_data;
1309 int used = file->out_used;
1313 if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) {
1314 if (GetLastError() != ERROR_IO_PENDING) {
1315 altos_set_last_windows_error();
1316 return LIBALTOS_ERROR;
1318 ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE);
1321 if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) {
1322 altos_set_last_windows_error();
1323 return LIBALTOS_ERROR;
1327 altos_set_last_windows_error();
1328 return LIBALTOS_ERROR;
1335 return LIBALTOS_SUCCESS;
1339 open_serial(char *full_name)
1344 handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
1345 0, NULL, OPEN_EXISTING,
1346 FILE_FLAG_OVERLAPPED, NULL);
1348 if (handle == INVALID_HANDLE_VALUE) {
1349 altos_set_last_windows_error();
1350 return INVALID_HANDLE_VALUE;
1353 if (!GetCommState(handle, &dcb)) {
1354 altos_set_last_windows_error();
1355 CloseHandle(handle);
1356 return INVALID_HANDLE_VALUE;
1358 dcb.BaudRate = CBR_9600;
1360 dcb.fParity = FALSE;
1361 dcb.fOutxCtsFlow = FALSE;
1362 dcb.fOutxDsrFlow = FALSE;
1363 dcb.fDtrControl = DTR_CONTROL_ENABLE;
1364 dcb.fDsrSensitivity = FALSE;
1365 dcb.fTXContinueOnXoff = FALSE;
1368 dcb.fErrorChar = FALSE;
1370 dcb.fRtsControl = RTS_CONTROL_ENABLE;
1371 dcb.fAbortOnError = FALSE;
1375 dcb.Parity = NOPARITY;
1376 dcb.StopBits = ONESTOPBIT;
1384 if (!SetCommState(handle, &dcb)) {
1385 altos_set_last_windows_error();
1386 CloseHandle(handle);
1387 return INVALID_HANDLE_VALUE;
1392 PUBLIC struct altos_file *
1393 altos_open(struct altos_device *device)
1395 struct altos_file *file = calloc (1, sizeof (struct altos_file));
1397 COMMTIMEOUTS timeouts;
1403 strcpy(full_name, "\\\\.\\");
1404 strcat(full_name, device->path);
1406 file->handle = INVALID_HANDLE_VALUE;
1408 for (i = 0; i < 5; i++) {
1409 file->handle = open_serial(full_name);
1410 if (file->handle != INVALID_HANDLE_VALUE)
1412 altos_set_last_windows_error();
1416 if (file->handle == INVALID_HANDLE_VALUE) {
1421 /* The FTDI driver doesn't appear to work right unless you open it twice */
1422 if (device->vendor == 0x0403) {
1423 CloseHandle(file->handle);
1424 file->handle = open_serial(full_name);
1425 if (file->handle == INVALID_HANDLE_VALUE) {
1431 timeouts.ReadIntervalTimeout = MAXDWORD;
1432 timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
1433 timeouts.ReadTotalTimeoutConstant = 1 << 30; /* almost forever */
1434 timeouts.WriteTotalTimeoutMultiplier = 0;
1435 timeouts.WriteTotalTimeoutConstant = 0;
1436 SetCommTimeouts(file->handle, &timeouts);
1438 file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1439 file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1445 altos_close(struct altos_file *file)
1447 HANDLE handle = file->handle;
1448 if (handle != INVALID_HANDLE_VALUE) {
1449 HANDLE ov_read = file->ov_read.hEvent;
1450 HANDLE ov_write = file->ov_write.hEvent;
1451 file->handle = INVALID_HANDLE_VALUE;
1452 file->ov_read.hEvent = INVALID_HANDLE_VALUE;
1453 file->ov_write.hEvent = INVALID_HANDLE_VALUE;
1454 PurgeComm(handle, PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_TXCLEAR);
1456 CloseHandle(handle);
1457 file->handle = INVALID_HANDLE_VALUE;
1458 CloseHandle(ov_read);
1459 CloseHandle(ov_write);
1464 altos_free(struct altos_file *file)
1471 altos_putchar(struct altos_file *file, char c)
1475 if (file->out_used == USB_BUF_SIZE) {
1476 ret = altos_flush(file);
1480 file->out_data[file->out_used++] = c;
1481 if (file->out_used == USB_BUF_SIZE)
1482 return altos_flush(file);
1483 return LIBALTOS_SUCCESS;
1487 altos_getchar(struct altos_file *file, int timeout)
1490 while (file->in_read == file->in_used) {
1491 if (file->handle == INVALID_HANDLE_VALUE) {
1492 altos_set_last_windows_error();
1493 return LIBALTOS_ERROR;
1495 ret = altos_fill(file, timeout);
1499 return file->in_data[file->in_read++];
1502 struct altos_bt_list *
1503 altos_bt_list_start(int inquiry_time)
1509 altos_bt_list_next(struct altos_bt_list *bt_list,
1510 struct altos_bt_device *device)
1516 altos_bt_list_finish(struct altos_bt_list *bt_list)
1522 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
1524 strncpy(device->name, name, sizeof (device->name));
1525 device->name[sizeof(device->name)-1] = '\0';
1526 strncpy(device->addr, addr, sizeof (device->addr));
1527 device->addr[sizeof(device->addr)-1] = '\0';
1531 altos_bt_open(struct altos_bt_device *device)