Add serial routines.
This commit is contained in:
parent
bf5342dc92
commit
2f2acc20e0
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ UNAME = $(shell uname)
|
||||
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
||||
LDFLAGS = -g
|
||||
|
||||
OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o rd5r.o gd77.o hid.o
|
||||
OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o rd5r.o gd77.o hid.o serial.o
|
||||
LIBS = -lusb-1.0
|
||||
|
||||
# Linux
|
||||
|
@ -5,7 +5,7 @@ GITCOUNT = $(shell git rev-list HEAD --count)
|
||||
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
||||
LDFLAGS = -g -s
|
||||
|
||||
OBJS = main.o util.o radio.o dfu-windows.o uv380.o md380.o rd5r.o gd77.o hid.o hid-windows.o
|
||||
OBJS = main.o util.o radio.o dfu-windows.o uv380.o md380.o rd5r.o gd77.o hid.o hid-windows.o serial.o
|
||||
LIBS = -lhid -lsetupapi
|
||||
|
||||
# Compiling Windows binary from Linux
|
||||
|
8
radio.c
8
radio.c
@ -68,6 +68,7 @@ void radio_disconnect()
|
||||
dfu_reboot();
|
||||
dfu_close();
|
||||
hid_close();
|
||||
serial_close();
|
||||
}
|
||||
|
||||
//
|
||||
@ -89,10 +90,15 @@ void radio_connect()
|
||||
// Try TYT MD family.
|
||||
ident = dfu_init(0x0483, 0xdf11);
|
||||
if (! ident) {
|
||||
// Try RD-5R.
|
||||
// Try RD-5R and GD-77.
|
||||
if (hid_init(0x15a2, 0x0073) >= 0)
|
||||
ident = hid_identify();
|
||||
}
|
||||
if (! ident) {
|
||||
// Try AT-D868UV.
|
||||
if (serial_init(0x28e9, 0x018a) >= 0)
|
||||
ident = serial_identify();
|
||||
}
|
||||
if (! ident) {
|
||||
fprintf(stderr, "No radio detected.\n");
|
||||
fprintf(stderr, "Check your USB cable!\n");
|
||||
|
631
serial.c
Normal file
631
serial.c
Normal file
@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Interface to virtual serial USB port.
|
||||
*
|
||||
* Copyright (C) 2018 Serge Vakulenko, KK6ABQ
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include "util.h"
|
||||
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
#include <windows.h>
|
||||
#include <malloc.h>
|
||||
static void *fd = INVALID_HANDLE_VALUE;
|
||||
static DCB saved_mode;
|
||||
#else
|
||||
#include <termios.h>
|
||||
static int fd = -1;
|
||||
static struct termios saved_mode;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
# include <libudev.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <CoreFoundation/CoreFoundation.h>
|
||||
# include <IOKit/IOBSD.h>
|
||||
# include <IOKit/storage/IOMedia.h>
|
||||
# include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
||||
# include <IOKit/usb/IOUSBLib.h>
|
||||
#endif
|
||||
|
||||
static char *dev_path;
|
||||
|
||||
static const unsigned char CMD_PRG[] = "PROGRAM";
|
||||
static const unsigned char CMD_QX[] = "QX\6";
|
||||
static const unsigned char CMD_ACK2[] = "\2";
|
||||
|
||||
//
|
||||
// Encode the speed in bits per second into bit value
|
||||
// accepted by cfsetspeed() function.
|
||||
// Return -1 when speed is not supported.
|
||||
//
|
||||
static int baud_encode(int bps)
|
||||
{
|
||||
#if defined(__WIN32__) || defined(WIN32) || B115200 == 115200
|
||||
// Windows, BSD, Mac OS: any baud rate allowed.
|
||||
return bps;
|
||||
#else
|
||||
// Linux: only a limited set of values permitted.
|
||||
switch (bps) {
|
||||
#ifdef B75
|
||||
case 75: return B75;
|
||||
#endif
|
||||
#ifdef B110
|
||||
case 110: return B110;
|
||||
#endif
|
||||
#ifdef B134
|
||||
case 134: return B134;
|
||||
#endif
|
||||
#ifdef B150
|
||||
case 150: return B150;
|
||||
#endif
|
||||
#ifdef B200
|
||||
case 200: return B200;
|
||||
#endif
|
||||
#ifdef B300
|
||||
case 300: return B300;
|
||||
#endif
|
||||
#ifdef B600
|
||||
case 600: return B600;
|
||||
#endif
|
||||
#ifdef B1200
|
||||
case 1200: return B1200;
|
||||
#endif
|
||||
#ifdef B1800
|
||||
case 1800: return B1800;
|
||||
#endif
|
||||
#ifdef B2400
|
||||
case 2400: return B2400;
|
||||
#endif
|
||||
#ifdef B4800
|
||||
case 4800: return B4800;
|
||||
#endif
|
||||
#ifdef B9600
|
||||
case 9600: return B9600;
|
||||
#endif
|
||||
#ifdef B19200
|
||||
case 19200: return B19200;
|
||||
#endif
|
||||
#ifdef B38400
|
||||
case 38400: return B38400;
|
||||
#endif
|
||||
#ifdef B57600
|
||||
case 57600: return B57600;
|
||||
#endif
|
||||
#ifdef B115200
|
||||
case 115200: return B115200;
|
||||
#endif
|
||||
#ifdef B230400
|
||||
case 230400: return B230400;
|
||||
#endif
|
||||
#ifdef B460800
|
||||
case 460800: return B460800;
|
||||
#endif
|
||||
#ifdef B500000
|
||||
case 500000: return B500000;
|
||||
#endif
|
||||
#ifdef B576000
|
||||
case 576000: return B576000;
|
||||
#endif
|
||||
#ifdef B921600
|
||||
case 921600: return B921600;
|
||||
#endif
|
||||
#ifdef B1000000
|
||||
case 1000000: return B1000000;
|
||||
#endif
|
||||
#ifdef B1152000
|
||||
case 1152000: return B1152000;
|
||||
#endif
|
||||
#ifdef B1500000
|
||||
case 1500000: return B1500000;
|
||||
#endif
|
||||
#ifdef B2000000
|
||||
case 2000000: return B2000000;
|
||||
#endif
|
||||
#ifdef B2500000
|
||||
case 2500000: return B2500000;
|
||||
#endif
|
||||
#ifdef B3000000
|
||||
case 3000000: return B3000000;
|
||||
#endif
|
||||
#ifdef B3500000
|
||||
case 3500000: return B3500000;
|
||||
#endif
|
||||
#ifdef B4000000
|
||||
case 4000000: return B4000000;
|
||||
#endif
|
||||
}
|
||||
printf("Unknown baud\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Send data to device.
|
||||
// Return number of bytes, or -1 on error.
|
||||
//
|
||||
int serial_write(const unsigned char *data, int len)
|
||||
{
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
DWORD written;
|
||||
|
||||
if (! WriteFile(fd, data, len, &written, 0))
|
||||
return -1;
|
||||
return written;
|
||||
#else
|
||||
return write(fd, data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Receive data from device.
|
||||
// Return number of bytes, or -1 on error.
|
||||
//
|
||||
int serial_read(unsigned char *data, int len, int timeout_msec)
|
||||
{
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
DWORD got;
|
||||
COMMTIMEOUTS ctmo;
|
||||
|
||||
// Reset the Windows RX timeout to the current timeout_msec
|
||||
// value, as it may have changed since the last read.
|
||||
//
|
||||
memset(&ctmo, 0, sizeof(ctmo));
|
||||
ctmo.ReadIntervalTimeout = 0;
|
||||
ctmo.ReadTotalTimeoutMultiplier = 0;
|
||||
ctmo.ReadTotalTimeoutConstant = timeout_msec;
|
||||
if (! SetCommTimeouts(fd, &ctmo)) {
|
||||
fprintf(stderr, "Cannot set timeouts in serial_read()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (! ReadFile(fd, data, len, &got, 0)) {
|
||||
fprintf(stderr, "serial_read: read error\n");
|
||||
exit(-1);
|
||||
}
|
||||
#else
|
||||
struct timeval timeout, to2;
|
||||
long got;
|
||||
fd_set rfds;
|
||||
|
||||
timeout.tv_sec = timeout_msec / 1000;
|
||||
timeout.tv_usec = timeout_msec % 1000 * 1000;
|
||||
again:
|
||||
to2 = timeout;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd, &rfds);
|
||||
|
||||
got = select(fd + 1, &rfds, 0, 0, &to2);
|
||||
if (got < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
if (trace_flag > 0)
|
||||
printf("serial_read: retry on select\n");
|
||||
goto again;
|
||||
}
|
||||
fprintf(stderr, "serial_read: select error: %s\n", strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
if (got == 0) {
|
||||
if (trace_flag > 0)
|
||||
printf("serial_read: no characters to read\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if ! defined(__WIN32__) && ! defined(WIN32)
|
||||
got = read(fd, data, (len > 1024) ? 1024 : len);
|
||||
if (got < 0) {
|
||||
fprintf(stderr, "serial_read: read error\n");
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
return got;
|
||||
}
|
||||
|
||||
//
|
||||
// Close the serial port.
|
||||
//
|
||||
void serial_close()
|
||||
{
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
if (fd != INVALID_HANDLE_VALUE) {
|
||||
SetCommState(fd, &saved_mode);
|
||||
CloseHandle(fd);
|
||||
fd = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (fd >= 0) {
|
||||
tcsetattr(fd, TCSANOW, &saved_mode);
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Open the serial port.
|
||||
// Return -1 on error.
|
||||
//
|
||||
int serial_open(const char *devname, int baud_rate)
|
||||
{
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
DCB new_mode;
|
||||
#else
|
||||
struct termios new_mode;
|
||||
#endif
|
||||
|
||||
#if defined(__WIN32__) || defined(WIN32)
|
||||
// Check for the Windows device syntax and bend a DOS device
|
||||
// into that syntax to allow higher COM numbers than 9
|
||||
//
|
||||
if (devname[0] != '\\') {
|
||||
// Prepend device prefix: COM23 -> \\.\COM23
|
||||
char *buf = alloca(5 + strlen(devname));
|
||||
if (! buf) {
|
||||
fprintf(stderr, "%s: Out of memory\n", devname);
|
||||
return -1;
|
||||
}
|
||||
strcpy(buf, "\\\\.\\");
|
||||
strcat(buf, devname);
|
||||
devname = buf;
|
||||
}
|
||||
|
||||
// Open port
|
||||
fd = CreateFile(devname, GENERIC_READ | GENERIC_WRITE,
|
||||
0, 0, OPEN_EXISTING, 0, 0);
|
||||
if (fd == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "%s: Cannot open\n", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set serial attributes
|
||||
memset(&saved_mode, 0, sizeof(saved_mode));
|
||||
if (! GetCommState(fd, &saved_mode)) {
|
||||
fprintf(stderr, "%s: Cannot get state\n", devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_mode = saved_mode;
|
||||
|
||||
new_mode.fDtrControl = DTR_CONTROL_ENABLE;
|
||||
new_mode.BaudRate = baud_rate;
|
||||
new_mode.ByteSize = 8;
|
||||
new_mode.StopBits = ONESTOPBIT;
|
||||
new_mode.Parity = 0;
|
||||
new_mode.fParity = FALSE;
|
||||
new_mode.fOutX = FALSE;
|
||||
new_mode.fInX = FALSE;
|
||||
new_mode.fOutxCtsFlow = FALSE;
|
||||
new_mode.fOutxDsrFlow = FALSE;
|
||||
new_mode.fRtsControl = RTS_CONTROL_ENABLE;
|
||||
new_mode.fNull = FALSE;
|
||||
new_mode.fAbortOnError = FALSE;
|
||||
new_mode.fBinary = TRUE;
|
||||
if (! SetCommState(fd, &new_mode)) {
|
||||
fprintf(stderr, "%s: Cannot set state\n", devname);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
// Encode baud rate.
|
||||
int baud_code = baud_encode(baud_rate);
|
||||
if (baud_code < 0) {
|
||||
fprintf(stderr, "%s: Bad baud rate %d\n", devname, baud_rate);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Open port
|
||||
fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
perror(devname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set serial attributes
|
||||
memset(&saved_mode, 0, sizeof(saved_mode));
|
||||
tcgetattr(fd, &saved_mode);
|
||||
|
||||
// 8n1, ignore parity
|
||||
memset(&new_mode, 0, sizeof(new_mode));
|
||||
new_mode.c_cflag = CS8 | CLOCAL | CREAD;
|
||||
new_mode.c_iflag = IGNBRK;
|
||||
new_mode.c_oflag = 0;
|
||||
new_mode.c_lflag = 0;
|
||||
new_mode.c_cc[VTIME] = 0;
|
||||
new_mode.c_cc[VMIN] = 1;
|
||||
cfsetispeed(&new_mode, baud_code);
|
||||
cfsetospeed(&new_mode, baud_code);
|
||||
tcflush(fd, TCIFLUSH);
|
||||
tcsetattr(fd, TCSANOW, &new_mode);
|
||||
|
||||
// Clear O_NONBLOCK flag.
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags >= 0)
|
||||
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Find a device path by vid/pid.
|
||||
//
|
||||
static char *find_path(int vid, int pid)
|
||||
{
|
||||
char *result = 0;
|
||||
|
||||
#if defined(__linux__)
|
||||
// Create the udev object.
|
||||
struct udev *udev = udev_new();
|
||||
if (! udev) {
|
||||
printf("Can't create udev\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a list of the devices in the 'tty' subsystem.
|
||||
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(enumerate, "tty");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
// For each item enumerated, figure out its information.
|
||||
struct udev_list_entry *dev_list_entry;
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
// Get the filename of the /sys entry for the device
|
||||
// and create a udev_device object (dev) representing it.
|
||||
const char *syspath = udev_list_entry_get_name(dev_list_entry);
|
||||
struct udev_device *comport = udev_device_new_from_syspath(udev, syspath);
|
||||
//printf("syspath = %s\n", syspath);
|
||||
|
||||
// Get the parent device with the subsystem/devtype pair
|
||||
// of "usb"/"usb_device".
|
||||
struct udev_device *parent = udev_device_get_parent_with_subsystem_devtype(comport,
|
||||
"usb", "usb_device");
|
||||
if (! parent) {
|
||||
//printf("Unable to find parent usb device.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the path to the device node in /dev.
|
||||
const char *devpath = udev_device_get_devnode(comport);
|
||||
//printf("devpath = %s\n", devpath);
|
||||
//printf("parent = %s\n", udev_device_get_devnode(parent));
|
||||
|
||||
const char *idVendor = udev_device_get_sysattr_value(parent, "idVendor");
|
||||
const char *idProduct = udev_device_get_sysattr_value(parent, "idProduct");
|
||||
if (! idVendor || ! idProduct) {
|
||||
// No vendor and product ID.
|
||||
continue;
|
||||
}
|
||||
//printf("vid = %s\n", idVendor);
|
||||
//printf("pid = %s\n", idProduct);
|
||||
|
||||
unsigned vendor_id = strtoul(idVendor, 0, 16);
|
||||
unsigned product_id = strtoul(idProduct, 0, 16);
|
||||
if (vendor_id != vid || product_id != pid) {
|
||||
// Wrong ID.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Print names of vendor and product.
|
||||
//const char *vendor = udev_device_get_sysattr_value(parent, "manufacturer");
|
||||
//const char *product = udev_device_get_sysattr_value(parent, "product");
|
||||
//printf("vendor = %s\n", vendor);
|
||||
//printf("product = %s\n", product);
|
||||
|
||||
// Return result.
|
||||
udev_device_unref(parent);
|
||||
result = strdup(devpath);
|
||||
break;
|
||||
}
|
||||
|
||||
// Free the enumerator object
|
||||
udev_enumerate_unref(enumerate);
|
||||
udev_unref(udev);
|
||||
return result;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// Create a list of the devices in the 'IOMedia' class.
|
||||
CFMutableDictionaryRef dict = IOServiceMatching(kIOMediaClass);
|
||||
if (! dict) {
|
||||
printf("Cannot create IO Service dictionary.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Select devices with attributes Removeable=True and Whole=True.
|
||||
CFDictionarySetValue(dict, CFSTR(kIOMediaRemovableKey), kCFBooleanTrue);
|
||||
CFDictionarySetValue(dict, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
|
||||
|
||||
io_iterator_t devices = IO_OBJECT_NULL;
|
||||
kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
dict, &devices);
|
||||
if (result != KERN_SUCCESS) {
|
||||
printf("Cannot find matching IO services.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// For each matching device, print out its information.
|
||||
io_object_t device;
|
||||
while ((device = IOIteratorNext(devices)) != MACH_PORT_NULL) {
|
||||
// Get device path.
|
||||
char devname[1024] = "/dev/r";
|
||||
CFStringRef ref = (CFStringRef) IORegistryEntrySearchCFProperty(device,
|
||||
kIOServicePlane, CFSTR(kIOBSDNameKey),
|
||||
kCFAllocatorDefault, kIORegistryIterateRecursively);
|
||||
if (! ref || ! CFStringGetCString(ref, devname + 6,
|
||||
sizeof(devname) - 6, kCFStringEncodingUTF8)) {
|
||||
// Cannot get device path.
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
// Get device size in bytes.
|
||||
long long size;
|
||||
ref = IORegistryEntryCreateCFProperty(device,
|
||||
CFSTR(kIOMediaSizeKey), kCFAllocatorDefault, 0);
|
||||
if (! ref || ! CFNumberGetValue((CFNumberRef)ref, kCFNumberLongLongType, &size)) {
|
||||
// Cannot get device size.
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
// Get a list of device characteristics.
|
||||
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)
|
||||
IORegistryEntrySearchCFProperty(device, kIOServicePlane,
|
||||
CFSTR(kIOPropertyDeviceCharacteristicsKey),
|
||||
kCFAllocatorDefault, kIORegistryIterateParents | kIORegistryIterateRecursively);
|
||||
if (! dict) {
|
||||
// Cannot get device characteristics.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get vendor and product names.
|
||||
char vendor[1024], product[1024];
|
||||
ref = CFDictionaryGetValue(dict, CFSTR(kIOPropertyVendorNameKey));
|
||||
if (! ref || ! CFStringGetCString(ref, vendor,
|
||||
sizeof(vendor), kCFStringEncodingUTF8)) {
|
||||
// Cannot get vendor name.
|
||||
continue;
|
||||
}
|
||||
ref = CFDictionaryGetValue(dict, CFSTR(kIOPropertyProductNameKey));
|
||||
if (! ref || ! CFStringGetCString(ref, product,
|
||||
sizeof(product), kCFStringEncodingUTF8)) {
|
||||
// Cannot get product name.
|
||||
continue;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
sprintf(buf, "%s - size %u MB, %s %s",
|
||||
devname, (unsigned) (size / 1000000), vendor, product);
|
||||
IOObjectRelease(device);
|
||||
devtab[ndev++] = strdup(buf);
|
||||
}
|
||||
|
||||
// Free the iterator object
|
||||
IOObjectRelease(devices);
|
||||
#else
|
||||
printf("Don't know how to get the list of CD devices on this system.\n");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// Connect to the specified device.
|
||||
// Initiate the programming session.
|
||||
//
|
||||
int serial_init(int vid, int pid)
|
||||
{
|
||||
dev_path = find_path(vid, pid);
|
||||
if (!dev_path) {
|
||||
if (trace_flag) {
|
||||
fprintf(stderr, "Cannot find USB device %04x:%04x\n",
|
||||
vid, pid);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Succeeded.
|
||||
printf("Serial port: %s\n", dev_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Send the command sequence and get back a response.
|
||||
//
|
||||
static int send_recv(const unsigned char *cmd, int cmdlen,
|
||||
unsigned char *response, int reply_len)
|
||||
{
|
||||
unsigned char *p;
|
||||
int len, i, got;
|
||||
|
||||
//
|
||||
// Send command.
|
||||
//
|
||||
if (trace_flag > 0) {
|
||||
fprintf(stderr, "----Send [%d] %x", cmdlen, cmd[0]);
|
||||
for (i=1; i<cmdlen; ++i)
|
||||
fprintf(stderr, "-%x", cmd[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if (serial_write(cmd, cmdlen) < 0) {
|
||||
fprintf(stderr, "%s: write error\n", dev_path);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//
|
||||
// Get response.
|
||||
//
|
||||
p = response;
|
||||
len = 0;
|
||||
while (len < reply_len) {
|
||||
got = serial_read(p, reply_len - len, 1000);
|
||||
if (! got)
|
||||
return 0;
|
||||
|
||||
p += got;
|
||||
len += got;
|
||||
}
|
||||
|
||||
if (trace_flag > 0) {
|
||||
fprintf(stderr, "----Recv [%d] %x", reply_len, response[0]);
|
||||
for (i=1; i<reply_len; ++i)
|
||||
fprintf(stderr, "-%x", response[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Query and return the device identification string.
|
||||
//
|
||||
const char *serial_identify()
|
||||
{
|
||||
static unsigned char reply[16];
|
||||
unsigned char ack[3];
|
||||
|
||||
if (serial_open(dev_path, 115200) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
send_recv(CMD_PRG, 7, ack, 3);
|
||||
if (ack[0] != CMD_QX[0] || ack[1] != CMD_QX[1] || ack[2] != CMD_QX[2]) {
|
||||
fprintf(stderr, "%s: Wrong PRG acknowledge %02x-%02x-%02x, expected %02x-%02x-%02x\n",
|
||||
__func__, ack[0], ack[1], ack[2], CMD_QX[0], CMD_QX[1], CMD_QX[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reply:
|
||||
// 49 44 38 36 38 55 56 45 00 56 31 30 32 00 00 06
|
||||
// I D 8 6 8 U V E V 1 0 2
|
||||
send_recv(CMD_ACK2, 1, reply, 16);
|
||||
|
||||
// Terminate the string.
|
||||
reply[8] = 0;
|
||||
return (char*)reply;
|
||||
}
|
12
util.h
12
util.h
@ -77,6 +77,18 @@ void hid_read_finish(void);
|
||||
void hid_write_block(int bno, unsigned char *data, int nbytes);
|
||||
void hid_write_finish(void);
|
||||
|
||||
//
|
||||
// Serial functions.
|
||||
//
|
||||
int serial_init(int vid, int pid);
|
||||
const char *serial_identify(void);
|
||||
void serial_close(void);
|
||||
//void serial_send_recv(const unsigned char *data, unsigned nbytes, unsigned char *rdata, unsigned rlength);
|
||||
//void serial_read_block(int bno, unsigned char *data, int nbytes);
|
||||
//void serial_read_finish(void);
|
||||
//void serial_write_block(int bno, unsigned char *data, int nbytes);
|
||||
//void serial_write_finish(void);
|
||||
|
||||
//
|
||||
// Delay in milliseconds.
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user