Subversion Repositories heizung

Rev

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;
}