Rev 5 | Blame | Compare with Previous | Last modification | View Log | RSS feed
/*
* (C) Copyright 2011, 2024 by Andreas Theofilu <andreas@theosys.at>
* All rights reserved!
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/signal.h>
#include <time.h>
#include <syslog.h>
#include <termios.h>
#include "usb_comm.h"
#define INTR_TIMEOUT 3000
#define BULK_TIMEOUT 3000
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* something magic about 64, garmin driver will not return more than
* 64 at a time. If you read less than 64 bytes the next read will
* just get the last of the 64 byte buffer.
*/
#define ASYNC_DATA_SIZE 64
#define PRIV_PKTID_SET_MODE 2
#define PRIV_PKTID_INFO_RESP 4
#define PRIV_PKTID_INFO_REQ 3
#define SERIAL_USB_VID_PL2303 0x067b
#define SERIAL_USB_PID_PL2303 0x2303
#define SERIAL_DIR_NONE 0
#define SERIAL_DIR_READ 1
#define SERIAL_DIR_WRITE 2
const char *USBdevice = NULL;
struct termios ttyset, ttyset_old;
static fd_set all_fds;
void signal_handler_IO (int status); /* definition of signal handler */
int wait_flag = TRUE; /* TRUE while no signal received */
SERDEV serialDev;
int serial_set_speed(SERDEV *ser, unsigned int speed, unsigned int stopbits);
void serial_set_device(const char *device)
{
USBdevice = device;
}
void serial_set_method(int mth, unsigned int vid, unsigned int pid)
{
serialDev.method = (mth != 0) ? 1 : 0;
if (!serialDev.method && (!vid || !pid))
serialDev.method = 1;
if (vid && pid)
{
serialDev.USB_VID = vid;
serialDev.USB_PID = pid;
}
}
/* Close the USB connection with the serial device. */
int serial_close()
{
int flag = 0;
if (serialDev.method && serialDev.fd != -1)
{
close(serialDev.fd);
serialDev.fd = -1;
serialDev.switch_fd = -1;
syslog(LOG_DAEMON | LOG_INFO,"Successful closed device %s", USBdevice);
USBdevice = NULL;
flag = 1;
}
else if (serialDev.handle != NULL )
{
usb_release_interface(serialDev.handle,0);
usb_close(serialDev.handle);
serialDev.handle = NULL;
serialDev.switch_fd = -1;
syslog(LOG_DAEMON | LOG_INFO,"Successful closed device %u:%u", serialDev.USB_VID, serialDev.USB_PID);
flag = 1;
}
if (!flag)
syslog(LOG_DAEMON | LOG_ERR,"Error closing serial device for controlling heating!");
return 0;
}
/*
Open the USB connection with the first Garmin device we find. Eventually,
I'd like to add the ability to select a particular device.
*/
int serial_open()
{
struct usb_bus * bi;
struct usb_device * di;
int i;
static unsigned int rates[] = {0, 4800, 9600, 19200, 38400, 57600};
struct sigaction saio;
char hv0[1024];
if (serialDev.method && serialDev.fd == -1)
{
if ((serialDev.fd = open(USBdevice, O_RDWR | O_NDELAY)) == -1)
{
syslog(LOG_DAEMON | LOG_ERR, "Error opening device %s: %s", USBdevice, strerror(errno));
return 0;
}
serialDev.switch_fd = serialDev.fd;
syslog(LOG_DAEMON | LOG_INFO, "Successful opened device %s", USBdevice);
return 1;
}
else if (!serialDev.method && serialDev.handle == NULL)
{
usb_init();
usb_find_busses();
usb_find_devices();
for (bi = usb_busses; bi != NULL; bi = bi->next )
{
for (di = bi->devices; di != NULL; di = di->next )
{
if (di->descriptor.idVendor == serialDev.USB_VID &&
di->descriptor.idProduct == serialDev.USB_PID)
{
syslog(LOG_DAEMON | LOG_INFO, "Found VID %04x, PID %04x on %s/%s!",
di->descriptor.idVendor,
di->descriptor.idProduct,
bi->dirname,
di->filename);
}
serialDev.handle = usb_open(di);
serialDev.read_bulk = 0;
if (serialDev.handle == NULL)
{
syslog(LOG_DAEMON | LOG_ERR, "usb_open failed: %s!",usb_strerror());
return 0;
}
if (usb_set_configuration(serialDev.handle, 1) < 0)
{
syslog(LOG_DAEMON | LOG_ERR, "usb_set_configuration failed: %s!",usb_strerror());
return 0;
}
if (usb_claim_interface(serialDev.handle,0) < 0)
{
syslog(LOG_DAEMON | LOG_ERR, "usb_claim_interface failed: %s!",usb_strerror());
return 0;
}
for (i = 0; i < di->config->interface->altsetting->bNumEndpoints; i++)
{
struct usb_endpoint_descriptor *ep;
ep = &di->config->interface->altsetting->endpoint[i];
switch (ep->bmAttributes & USB_ENDPOINT_TYPE_MASK )
{
case USB_ENDPOINT_TYPE_BULK:
if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK )
serialDev.bulk_in = ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
else
serialDev.bulk_out = ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
break;
case USB_ENDPOINT_TYPE_INTERRUPT:
if ( ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK )
serialDev.intr_in = ep->bEndpointAddress & USB_ENDPOINT_ADDRESS_MASK;
break;
default:
break;
}
}
break;
}
if (serialDev.handle != NULL )
break;
}
if (serialDev.handle == NULL)
syslog(LOG_DAEMON | LOG_ERR, "Couldn't detect any serial device!");
}
return (serialDev.handle != NULL);
}
int serial_set_speed(SERDEV *ser, unsigned int speed, unsigned int stopbits)
{
unsigned int rate;
if (!ser)
return 0;
if (speed < 300)
rate = B0;
else if (speed < 1200)
rate = B300;
else if (speed < 2400)
rate = B1200;
else if (speed < 4800)
rate = B2400;
else if (speed < 9600)
rate = B4800;
else if (speed < 19200)
rate = B9600;
else if (speed < 38400)
rate = B19200;
else if (speed < 57600)
rate = B38400;
else if (speed < 115200)
rate = B57600;
else
rate = B115200;
tcflush(ser->fd, TCIOFLUSH); /* toss stale data */
if (rate != cfgetispeed(&ttyset) || stopbits != 1)
{
cfsetispeed(&ttyset, (speed_t)rate);
cfsetospeed(&ttyset, (speed_t)rate);
ttyset.c_cflag &=~ CSIZE;
ttyset.c_cflag |= (CSIZE & (stopbits == 2 ? CS7 : CS8));
if (tcsetattr(ser->fd, TCSANOW, &ttyset) != 0)
return 0;
tcflush(ser->fd, TCIOFLUSH);
}
return 1;
}