X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=libaltos%2Flibaltos.c;h=fc949c7020a2e8143f5c5f83238ebda3cb4b1003;hp=d7b266cf08936f23abd1a18003b26c4cc0f9012e;hb=bd8d061d0f63158b5b03814d77cb76fdf5a0abad;hpb=f7a56152808c7838c1886884bb77de2705ab076c diff --git a/libaltos/libaltos.c b/libaltos/libaltos.c index d7b266cf..fc949c70 100644 --- a/libaltos/libaltos.c +++ b/libaltos/libaltos.c @@ -148,6 +148,8 @@ altos_open(struct altos_device *device) return NULL; } cfmakeraw(&term); + cfsetospeed(&term, B9600); + cfsetispeed(&term, B9600); #ifdef USE_POLL term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; @@ -476,26 +478,26 @@ usb_tty(char *sys) return tty; } - /* Check for ttyACMx style names + /* Check for tty/ttyACMx style names */ - ntty = scandir(endpoint_full, &namelist, + tty_dir = cc_fullname(endpoint_full, "tty"); + ntty = scandir(tty_dir, &namelist, dir_filter_tty, alphasort); + free (tty_dir); if (ntty > 0) { - free(endpoint_full); tty = cc_fullname("/dev", namelist[0]->d_name); + free(endpoint_full); free(namelist); return tty; } - /* Check for tty/ttyACMx style names + /* Check for ttyACMx style names */ - tty_dir = cc_fullname(endpoint_full, "tty"); - free(endpoint_full); - ntty = scandir(tty_dir, &namelist, + ntty = scandir(endpoint_full, &namelist, dir_filter_tty, alphasort); - free (tty_dir); + free(endpoint_full); if (ntty > 0) { tty = cc_fullname("/dev", namelist[0]->d_name); free(namelist); @@ -604,6 +606,12 @@ altos_list_start(void) 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) { @@ -728,30 +736,36 @@ struct altos_file * altos_bt_open(struct altos_bt_device *device) { struct sockaddr_rc addr = { 0 }; - int s, status; + int status, i; struct altos_file *file; file = calloc(1, sizeof (struct altos_file)); if (!file) goto no_file; - file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (file->fd < 0) { - altos_set_last_posix_error(); - goto no_sock; - } - addr.rc_family = AF_BLUETOOTH; addr.rc_channel = 1; str2ba(device->addr, &addr.rc_bdaddr); - status = connect(file->fd, - (struct sockaddr *)&addr, - sizeof(addr)); + 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; } - sleep(1); + usleep(100 * 1000); #ifdef USE_POLL pipe(file->pipe); @@ -760,7 +774,7 @@ altos_bt_open(struct altos_bt_device *device) #endif return file; no_link: - close(s); + close(file->fd); no_sock: free(file); no_file: @@ -783,6 +797,7 @@ no_file: struct altos_list { io_iterator_t iterator; + int ftdi; }; static int @@ -840,8 +855,21 @@ altos_list_start(void) int i; ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator); - if (ret != kIOReturnSuccess) + 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; } @@ -859,10 +887,15 @@ altos_list_next(struct altos_list *list, struct altos_device *device) if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) || !get_number (object, CFSTR(kUSBProductID), &device->product)) continue; - if (device->vendor != 0xfffe) - continue; - if (device->product < 0x000a || 0x0013 < device->product) - continue; + if (list->ftdi) { + if (device->vendor != 0x0403) + continue; + } else { + if (device->vendor != 0xfffe) + continue; + if (device->product < 0x000a || 0x0013 < device->product) + continue; + } if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) && get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) && get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) { @@ -933,6 +966,7 @@ altos_bt_open(struct altos_bt_device *device) struct altos_list { HDEVINFO dev_info; int index; + int ftdi; }; #define USB_BUF_SIZE 64 @@ -949,6 +983,24 @@ struct altos_file { 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) { + va_start(a, fmt); + vfprintf(log, fmt, a); + va_end(a); + fflush(log); + } +} + static void _altos_set_last_windows_error(char *file, int line) { @@ -962,7 +1014,7 @@ _altos_set_last_windows_error(char *file, int line) sizeof (message) / sizeof (TCHAR), NULL); if (error != ERROR_SUCCESS) - printf ("%s:%d %s\n", file, line, message); + log_message ("%s:%d %s\n", file, line, message); altos_set_last_error(error, message); } @@ -983,6 +1035,26 @@ altos_list_start(void) 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; } @@ -1013,28 +1085,32 @@ altos_list_next(struct altos_list *list, struct altos_device *device) KEY_READ); if (dev_key == INVALID_HANDLE_VALUE) { altos_set_last_windows_error(); - printf("cannot open device registry key\n"); continue; } - /* Fetch symbolic name for this device and parse out - * the vid/pid/serial info */ - symbolic_len = sizeof(symbolic); - result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL, - symbolic, &symbolic_len); - if (result != 0) { - altos_set_last_windows_error(); - printf("cannot find SymbolicName value\n"); - RegCloseKey(dev_key); - continue; + if (list->ftdi) { + vid = 0x0403; + pid = 0x6015; + serial = 0; + } else { + /* 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(); + RegCloseKey(dev_key); + continue; + } + vid = pid = serial = 0; + 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); } - vid = pid = serial = 0; - 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); /* Fetch the com port name */ port_len = sizeof (port); @@ -1043,7 +1119,6 @@ altos_list_next(struct altos_list *list, struct altos_device *device) RegCloseKey(dev_key); if (result != 0) { altos_set_last_windows_error(); - printf("failed to get PortName\n"); continue; } @@ -1059,7 +1134,6 @@ altos_list_next(struct altos_list *list, struct altos_device *device) &friendlyname_len)) { altos_set_last_windows_error(); - printf("Failed to get friendlyname\n"); continue; } device->vendor = vid; @@ -1071,10 +1145,8 @@ altos_list_next(struct altos_list *list, struct altos_device *device) return 1; } result = GetLastError(); - if (result != ERROR_NO_MORE_ITEMS) { + if (result != ERROR_NO_MORE_ITEMS) altos_set_last_windows_error(); - printf ("SetupDiEnumDeviceInfo failed error %d\n", (int) result); - } return 0; } @@ -1133,6 +1205,7 @@ altos_wait_read(struct altos_file *file, int timeout) return LIBALTOS_TIMEOUT; break; default: + altos_set_last_windows_error(); return LIBALTOS_ERROR; } return LIBALTOS_SUCCESS; @@ -1170,7 +1243,6 @@ altos_flush(struct altos_file *file) if (!WriteFile(file->handle, data, used, &put, &file->ov_write)) { if (GetLastError() != ERROR_IO_PENDING) { altos_set_last_windows_error(); - printf ("\tflush write error\n"); return LIBALTOS_ERROR; } ret = WaitForSingleObject(file->ov_write.hEvent, INFINITE); @@ -1178,13 +1250,11 @@ altos_flush(struct altos_file *file) case WAIT_OBJECT_0: if (!GetOverlappedResult(file->handle, &file->ov_write, &put, FALSE)) { altos_set_last_windows_error(); - printf ("\tflush result error\n"); return LIBALTOS_ERROR; } break; default: altos_set_last_windows_error(); - printf ("\tflush wait error\n"); return LIBALTOS_ERROR; } } @@ -1195,29 +1265,97 @@ altos_flush(struct altos_file *file) 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 = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, NULL); + + file->handle = INVALID_HANDLE_VALUE; + + for (i = 0; i < 5; i++) { + file->handle = open_serial(full_name); + if (file->handle != INVALID_HANDLE_VALUE) + break; + Sleep(100); + } + if (file->handle == INVALID_HANDLE_VALUE) { - altos_set_last_windows_error(); - printf ("cannot open %s\n", full_name); free(file); return NULL; } - file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, 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; @@ -1226,6 +1364,9 @@ altos_open(struct altos_device *device) 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; } @@ -1270,8 +1411,10 @@ altos_getchar(struct altos_file *file, int timeout) { int ret; while (file->in_read == file->in_used) { - if (file->handle == INVALID_HANDLE_VALUE) + if (file->handle == INVALID_HANDLE_VALUE) { + altos_set_last_windows_error(); return LIBALTOS_ERROR; + } ret = altos_fill(file, timeout); if (ret) return ret;