X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=libaltos%2Flibaltos.c;h=4e3bc2c51b2d5b1f7fcd2eb9c8d090118657a13a;hp=ca56746a643d8cd0de773ceb180e0c2ea95320b3;hb=5872bd10df14b47de0e541bff16d9220af0558aa;hpb=670034eef48d63cdaec8d271fa93da984ffe2ea9 diff --git a/libaltos/libaltos.c b/libaltos/libaltos.c index ca56746a..4e3bc2c5 100644 --- a/libaltos/libaltos.c +++ b/libaltos/libaltos.c @@ -53,6 +53,8 @@ altos_get_last_error(struct altos_error *error) #ifdef DARWIN +#include + #undef USE_POLL /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */ @@ -641,6 +643,49 @@ altos_list_finish(struct altos_list *usbdevs) 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; @@ -704,7 +749,8 @@ altos_bt_list_next(struct altos_bt_list *bt_list, return 0; ii = &bt_list->ii[bt_list->rsp]; - ba2str(&ii->bdaddr, device->addr); + 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), @@ -736,30 +782,42 @@ 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) + if (!file) { + errno = ENOMEM; + altos_set_last_posix_error(); goto no_file; - file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (file->fd < 0) { + } + 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; } - addr.rc_family = AF_BLUETOOTH; - addr.rc_channel = 1; - str2ba(device->addr, &addr.rc_bdaddr); + 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)); + 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); @@ -768,7 +826,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: @@ -809,7 +867,7 @@ get_string(io_object_t object, CFStringRef entry, char *result, int result_len) got_string = CFStringGetCString(entry_as_string, result, result_len, kCFStringEncodingASCII); - + CFRelease(entry_as_string); if (got_string) return 1; @@ -822,7 +880,7 @@ get_number(io_object_t object, CFStringRef entry, int *result) { CFTypeRef entry_as_number; Boolean got_number; - + entry_as_number = IORegistryEntrySearchCFProperty (object, kIOServicePlane, entry, @@ -877,19 +935,10 @@ altos_list_next(struct altos_list *list, struct altos_device *device) 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 (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))) { @@ -977,6 +1026,29 @@ 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) { + 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) { @@ -990,7 +1062,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); } @@ -1061,7 +1133,6 @@ 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; } @@ -1077,7 +1148,6 @@ altos_list_next(struct altos_list *list, struct altos_device *device) symbolic, &symbolic_len); if (result != 0) { altos_set_last_windows_error(); - printf("cannot find SymbolicName value\n"); RegCloseKey(dev_key); continue; } @@ -1097,7 +1167,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; } @@ -1113,7 +1182,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; @@ -1125,10 +1193,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; } @@ -1187,6 +1253,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; @@ -1224,7 +1291,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); @@ -1232,13 +1298,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; } } @@ -1249,30 +1313,98 @@ 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; - DCB dcb; + 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); - if (file->handle == INVALID_HANDLE_VALUE) { + + 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(); - printf ("cannot open %s\n", full_name); + Sleep(100); + } + + if (file->handle == INVALID_HANDLE_VALUE) { 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; @@ -1281,10 +1413,8 @@ altos_open(struct altos_device *device) timeouts.WriteTotalTimeoutConstant = 0; SetCommTimeouts(file->handle, &timeouts); - if (GetCommState(file->handle, &dcb)) { - dcb.BaudRate = CBR_9600; - (void) SetCommState(file->handle, &dcb); - } + file->ov_read.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + file->ov_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); return file; } @@ -1292,13 +1422,19 @@ altos_open(struct altos_device *device) PUBLIC void altos_close(struct altos_file *file) { - if (file->handle != INVALID_HANDLE_VALUE) { - CloseHandle(file->handle); + 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; - SetEvent(file->ov_read.hEvent); - SetEvent(file->ov_write.hEvent); - CloseHandle(file->ov_read.hEvent); - CloseHandle(file->ov_write.hEvent); + CloseHandle(ov_read); + CloseHandle(ov_write); } } @@ -1330,8 +1466,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;