#ifdef DARWIN
+#include <unistd.h>
+
#undef USE_POLL
/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
return NULL;
}
cfmakeraw(&term);
+ cfsetospeed(&term, B9600);
+ cfsetispeed(&term, B9600);
#ifdef USE_POLL
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
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);
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)
{
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);
#endif
return file;
no_link:
- close(s);
+ close(file->fd);
no_sock:
free(file);
no_file:
struct altos_list {
io_iterator_t iterator;
+ int ftdi;
};
static int
got_string = CFStringGetCString(entry_as_string,
result, result_len,
kCFStringEncodingASCII);
-
+
CFRelease(entry_as_string);
if (got_string)
return 1;
{
CFTypeRef entry_as_number;
Boolean got_number;
-
+
entry_as_number = IORegistryEntrySearchCFProperty (object,
kIOServicePlane,
entry,
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;
}
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 (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))) {
struct altos_list {
HDEVINFO dev_info;
int index;
+ int ftdi;
};
#define USB_BUF_SIZE 64
OVERLAPPED ov_write;
};
+#include <stdarg.h>
+
+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)
{
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);
}
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;
}
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);
RegCloseKey(dev_key);
if (result != 0) {
altos_set_last_windows_error();
- printf("failed to get PortName\n");
continue;
}
&friendlyname_len))
{
altos_set_last_windows_error();
- printf("Failed to get friendlyname\n");
continue;
}
device->vendor = vid;
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;
}
return LIBALTOS_TIMEOUT;
break;
default:
+ altos_set_last_windows_error();
return LIBALTOS_ERROR;
}
return LIBALTOS_SUCCESS;
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);
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;
}
}
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);
- 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;
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;
}
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;
- SetEvent(file->ov_read.hEvent);
- SetEvent(file->ov_write.hEvent);
- CloseHandle(file->ov_read.hEvent);
- CloseHandle(file->ov_write.hEvent);
+ 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;
+ CloseHandle(ov_read);
+ CloseHandle(ov_write);
}
}
{
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;