[Nut-upsdev] Re: [Nut-upsuser] Ablerex 625L USB version
Peter Selinger
selinger at mathstat.dal.ca
Thu Feb 1 20:41:29 CET 2007
Hi Jon,
your patches are malformed because (presumably) your email client
wrapped this lines. Could you please send these as a unified diff
("diff -u"), and send them in attachments, rather than as a
copy-and-paste?
Thanks, -- Peter
Jon Gough wrote:
>
> Peter,
> Here are the files I have worked on. I hope I have diff'd them
> correctly. I have not touched the megatec_ser.c file so I have not
> included it. I have now got knutclient talking to the driver and it
> seems to be displaying what it should. So as a first pass this will
> work with the Upsonic CS1500 UPS that reports itself as Ablerex.
>
> Regards
> Jon
>
> *** megatec.c.orig 2007-01-29 08:12:19.000000000 +1100
> --- megatec.c 2007-01-31 18:28:33.000000000 +1100
> ***************
> *** 243,251 ****
> char buffer[RECV_BUFFER_LEN];
> int ret;
>
> ! upsdebugx(2, "Sending \"Q1\" command...");
> ! comm->send("Q1%c", ENDCHAR);
> ret = comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR, IGNCHARS);
> if (ret < Q1_CMD_REPLY_LEN) {
> upsdebugx(2, "Wrong answer to \"Q1\" command.");
>
> --- 243,253 ----
> char buffer[RECV_BUFFER_LEN];
> int ret;
>
> ! upsdebugx(2, "check_ups: Sending \"Q1\" command...");
> ! ret = comm->send("Q1%c", ENDCHAR);
> ! upsdebugx(4, "check_ups: getting receive stuff, ignchars: %s,
> ret: %i", IGNCHARS, ret);
> ret = comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR, IGNCHARS);
> + upsdebugx(4, "got receive stuff: rc = %i, buffer: %s", ret, buffer);
> if (ret < Q1_CMD_REPLY_LEN) {
> upsdebugx(2, "Wrong answer to \"Q1\" command.");
>
> ***************
> *** 265,270 ****
> --- 267,273 ----
>
> upsdebugx(1, "Asking for UPS information (\"I\" command)...");
> comm->send("I%c", ENDCHAR);
> + upsdebugx(4, "get_ups_info: getting receive stuff, ignchars:
> %s", IGNCHARS);
> ret = comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR, IGNCHARS);
> if (ret < I_CMD_REPLY_LEN) {
> upsdebugx(1, "UPS doesn't return any information
> about itself.");
> ***************
> *** 295,300 ****
> --- 298,304 ----
>
> upsdebugx(1, "Asking for UPS power ratings (\"F\" command)...");
> comm->send("F%c", ENDCHAR);
> + upsdebugx(4, "get_firmware_values: getting receive stuff,
> ignchars: %s", IGNCHARS);
> ret = comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR, IGNCHARS);
> if (ret < F_CMD_REPLY_LEN) {
> upsdebugx(1, "UPS doesn't return any information
> about its power ratings.");
> ***************
> *** 318,323 ****
> --- 322,328 ----
>
> upsdebugx(1, "Asking for UPS status (\"Q1\" command)...");
> comm->send("Q1%c", ENDCHAR);
> + upsdebugx(4, "run_query: getting receive stuff, ignchars:
> %s", IGNCHARS);
> ret = comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR, IGNCHARS);
> if (ret < Q1_CMD_REPLY_LEN) {
> upsdebugx(1, "UPS doesn't return any information
> about its status.");
> ***************
> *** 564,571 ****
> {
> upslogx(LOG_INFO, "Shutting down UPS immediately.");
>
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> ! ser_send_pace(upsfd, SEND_PACE, "S%02dR%04d%c",
> shutdown_delay, start_delay, ENDCHAR);
> }
>
>
> --- 569,576 ----
> {
> upslogx(LOG_INFO, "Shutting down UPS immediately.");
>
> ! comm->send("C%c", ENDCHAR);
> ! comm->send("S%02dR%04d%c%c", shutdown_delay, start_delay, ENDCHAR);
> }
>
>
> ***************
> *** 581,589 ****
> */
>
> if (strcasecmp(cmdname, "test.battery.start.deep") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "TL%c", ENDCHAR);
>
> ! if (ser_get_line(upsfd, buffer, RECV_BUFFER_LEN,
> ENDCHAR, IGNCHARS, READ_TIMEOUT, 0) > 0) {
> upslogx(LOG_NOTICE, "test.battery.start.deep
> not supported by UPS.");
> } else {
> upslogx(LOG_INFO, "Deep battery test started.");
> --- 586,595 ----
> */
>
> if (strcasecmp(cmdname, "test.battery.start.deep") == 0) {
> ! comm->send("TL%c", ENDCHAR);
>
> ! upsdebugx(4, "instcmd1: getting receive stuff, ignchars: %s",
> IGNCHARS);
> ! if (comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR,
> IGNCHARS) > 0) {
> upslogx(LOG_NOTICE, "test.battery.start.deep
> not supported by UPS.");
> } else {
> upslogx(LOG_INFO, "Deep battery test started.");
> ***************
> *** 593,601 ****
> }
>
> if (strcasecmp(cmdname, "test.battery.start") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "T%c", ENDCHAR);
>
> ! if (ser_get_line(upsfd, buffer, RECV_BUFFER_LEN,
> ENDCHAR, IGNCHARS, READ_TIMEOUT, 0) > 0) {
> upslogx(LOG_NOTICE, "test.battery.start not
> supported by UPS.");
> } else {
> upslogx(LOG_INFO, "Battery test started.");
> --- 599,608 ----
> }
>
> if (strcasecmp(cmdname, "test.battery.start") == 0) {
> ! comm->send("T%c", ENDCHAR);
>
> ! upsdebugx(4, "instcmd2: getting receive stuff, ignchars: %s",
> IGNCHARS);
> ! if (comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR,
> IGNCHARS) > 0) {
> upslogx(LOG_NOTICE, "test.battery.start not
> supported by UPS.");
> } else {
> upslogx(LOG_INFO, "Battery test started.");
> ***************
> *** 605,613 ****
> }
>
> if (strcasecmp(cmdname, "test.battery.stop") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "CT%c", ENDCHAR);
>
> ! if (ser_get_line(upsfd, buffer, RECV_BUFFER_LEN,
> ENDCHAR, IGNCHARS, READ_TIMEOUT, 0) > 0) {
> upslogx(LOG_NOTICE, "test.battery.stop not
> supported by UPS.");
> } else {
> upslogx(LOG_INFO, "Battery test stopped.");
> --- 612,621 ----
> }
>
> if (strcasecmp(cmdname, "test.battery.stop") == 0) {
> ! comm->send("CT%c", ENDCHAR);
>
> ! upsdebugx(4, "instcmd3: getting receive stuff, ignchars: %s",
> IGNCHARS);
> ! if (comm->recv(buffer, RECV_BUFFER_LEN, ENDCHAR,
> IGNCHARS) > 0) {
> upslogx(LOG_NOTICE, "test.battery.stop not
> supported by UPS.");
> } else {
> upslogx(LOG_INFO, "Battery test stopped.");
> ***************
> *** 617,626 ****
> }
>
> if (strcasecmp(cmdname, "shutdown.return") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> ! ser_send_pace(upsfd, SEND_PACE, "S%02dR%04d%c",
> shutdown_delay, start_delay, ENDCHAR);
>
> upslogx(LOG_INFO, "Shutdown (return) initiated.");
>
> --- 625,634 ----
> }
>
> if (strcasecmp(cmdname, "shutdown.return") == 0) {
> ! comm->send("C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> ! comm->send("S%02dR%04d%c", shutdown_delay,
> start_delay, ENDCHAR);
>
> upslogx(LOG_INFO, "Shutdown (return) initiated.");
>
> ***************
> *** 628,637 ****
> }
>
> if (strcasecmp(cmdname, "shutdown.stayoff") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> ! ser_send_pace(upsfd, SEND_PACE, "S%02dR0000%c",
> shutdown_delay, ENDCHAR);
>
> upslogx(LOG_INFO, "Shutdown (stayoff) initiated.");
>
> --- 636,645 ----
> }
>
> if (strcasecmp(cmdname, "shutdown.stayoff") == 0) {
> ! comm->send("C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> ! comm->send("S%02dR0000%c%c", shutdown_delay, ENDCHAR);
>
> upslogx(LOG_INFO, "Shutdown (stayoff) initiated.");
>
> ***************
> *** 639,645 ****
> }
>
> if (strcasecmp(cmdname, "shutdown.stop") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> upslogx(LOG_INFO, "Shutdown canceled.");
> --- 647,653 ----
> }
>
> if (strcasecmp(cmdname, "shutdown.stop") == 0) {
> ! comm->send("C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> upslogx(LOG_INFO, "Shutdown canceled.");
> ***************
> *** 648,654 ****
> }
>
> if (strcasecmp(cmdname, "load.on") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> upslogx(LOG_INFO, "Turning load on.");
> --- 656,662 ----
> }
>
> if (strcasecmp(cmdname, "load.on") == 0) {
> ! comm->send("C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> upslogx(LOG_INFO, "Turning load on.");
> ***************
> *** 657,666 ****
> }
>
> if (strcasecmp(cmdname, "load.off") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> ! ser_send_pace(upsfd, SEND_PACE, "S00R0000%c", ENDCHAR);
>
> upslogx(LOG_INFO, "Turning load off.");
>
> --- 665,674 ----
> }
>
> if (strcasecmp(cmdname, "load.off") == 0) {
> ! comm->send("C%c", ENDCHAR);
> watchdog_enabled = 0;
>
> ! comm->send("S00R0000%c%c", ENDCHAR);
>
> upslogx(LOG_INFO, "Turning load off.");
>
> ***************
> *** 680,687 ****
> }
>
> if (strcasecmp(cmdname, "reset.watchdog") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "C%c", ENDCHAR);
> ! ser_send_pace(upsfd, SEND_PACE, "S%02dR0001%c",
> watchdog_timeout, ENDCHAR);
>
> if (watchdog_enabled) {
> upsdebugx(2, "Resetting the UPS watchdog.");
> --- 688,695 ----
> }
>
> if (strcasecmp(cmdname, "reset.watchdog") == 0) {
> ! comm->send("C%c", ENDCHAR);
> ! comm->send("S%02dR0001%c", watchdog_timeout, ENDCHAR);
>
> if (watchdog_enabled) {
> upsdebugx(2, "Resetting the UPS watchdog.");
> ***************
> *** 694,700 ****
> }
>
> if (strcasecmp(cmdname, "beeper.toggle") == 0) {
> ! ser_send_pace(upsfd, SEND_PACE, "Q%c", ENDCHAR);
>
> upslogx(LOG_INFO, "Toggling UPS beeper.");
>
> --- 702,708 ----
> }
>
> if (strcasecmp(cmdname, "beeper.toggle") == 0) {
> ! comm->send("Q%c", ENDCHAR);
>
> upslogx(LOG_INFO, "Toggling UPS beeper.");
>
> ***************
> *** 758,778 ****
>
> void upsdrv_banner(void)
> {
> ! printf("Network UPS Tools %s - Megatec protocol driver %s
> [%s]\n", UPS_VERSION, DRV_VERSION, progname);
> printf("Carlos Rodrigues (c) 2003-2007\n\n");
> }
>
>
> void upsdrv_initups(void)
> {
> ! upsfd = ser_open(device_path);
> ! ser_set_speed(upsfd, device_path, B2400);
> }
>
>
> void upsdrv_cleanup(void)
> {
> ! ser_close(upsfd, device_path);
> }
>
>
> --- 766,785 ----
>
> void upsdrv_banner(void)
> {
> ! printf("Network UPS Tools - Megatec protocol driver %s[%s]
> (%s)\n", DRV_VERSION, comm->name, UPS_VERSION);
> printf("Carlos Rodrigues (c) 2003-2007\n\n");
> }
>
>
> void upsdrv_initups(void)
> {
> ! comm->open(device_path);
> }
>
>
> void upsdrv_cleanup(void)
> {
> ! comm->close(device_path);
> }
>
> *** megatec.h.orig 2007-01-29 08:12:19.000000000 +1100
> --- megatec.h 2007-01-29 12:55:31.000000000 +1100
> ***************
> *** 1,5 ****
> /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: t; -*-
> ! *
> * megatec.h: support for Megatec protocol based UPSes
> *
> * Copyright (C) Carlos Rodrigues <carlos.efr at mail.telepac.pt>
> --- 1,5 ----
> /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: t; -*-
> ! *
> * megatec.h: support for Megatec protocol based UPSes
> *
> * Copyright (C) Carlos Rodrigues <carlos.efr at mail.telepac.pt>
> ***************
> *** 22,24 ****
> --- 22,36 ----
> */
>
> #define DRV_VERSION "1.5"
> +
> + /* comm driver */
> + typedef struct {
> + const char *name;
> + int (*open)(const char*param);
> + void (*close)();
> + int (*send)(const char *fmt,...);
> + int (*recv)(char *buffer,size_t buffer_len,char
> endchar,const char *ignchars);
> + } megatec_comm_t;
> +
> + extern megatec_comm_t* comm;
> +
>
> *** megatec_usb.c.orig 2007-02-01 19:01:06.000000000 +1100
> --- megatec_usb.c 2007-02-01 15:06:56.000000000 +1100
> ***************
> *** 0 ****
> --- 1,422 ----
> + /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: t; -*-
> + *
> + * megatec_usb.c: usb communication layer for Megatec protocol based UPSes
> + *
> + * Copyright (C) Andrey Lelikov <nut-driver at lelik.org>
> + *
> + * megatec_usb.c created on 3-Oct-2006
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + */
> +
> + #include "main.h"
> + #include "megatec.h"
> + #include "libusb.h"
> +
> + #include <stdio.h>
> + #include <limits.h>
> + #include <string.h>
> +
> + /*
> + This is a communication driver for "USB HID" UPS-es which use proprietary
> + usb-to-serial converter and speak megatec protocol. Usually these are cheap
> + models and usb-to-serial converter is a huge oem hack - HID tables are bogus,
> + device has no UPS reports, etc.
> + This driver has a table of all known devices which has pointers
> to device-
> + specific communication functions (namely send a string to UPS and
> read a string
> + from it). Driver takes care of detection, opening a usb device, string
> + formatting etc. So in order to add support for another
> usb-to-serial device one
> + only needs to implement device-specific get/set functions and add
> an entry into
> + KnownDevices table.
> +
> + */
> +
> + static communication_subdriver_t *usb = &usb_subdriver;
> + static usb_dev_handle *udev=NULL;
> + static HIDDevice hiddevice;
> +
> + static int comm_usb_recv(char *buffer,size_t buffer_len,char
> endchar,const char *ignchars);
> +
> + typedef struct
> + {
> + uint16_t vid;
> + uint16_t pid;
> + int (*get_data)(char *buffer,int buffer_size);
> + int (*set_data)(const char *str);
> + } usb_ups_t;
> +
> + usb_ups_t *usb_ups_device = NULL;
> +
> + /*
> + All devices known to this driver go here
> + along with their set/get routines
> + */
> +
> + static int get_data_agiler(char *buffer,int buffer_size);
> + static int set_data_agiler(const char *str);
> + static int get_data_ablerex(char *buffer,int buffer_size);
> + static int set_data_ablerex(const char *str);
> +
> + static usb_ups_t KnownDevices[]={
> + { 0x05b8, 0x0000, get_data_agiler, set_data_agiler },
> + { 0xffff, 0x0000, get_data_ablerex, set_data_ablerex },
> + { .vid=0 } /* end of list */
> + };
> +
> + static int comm_usb_match(HIDDevice *d, void *privdata)
> + {
> + usb_ups_t *p;
> + upsdebugx(4, "comm_usb_match");
> + for (p=KnownDevices;p->vid!=0;p++)
> + {
> + if ( (p->vid==d->VendorID) && (p->pid==d->ProductID) )
> + {
> + usb_ups_device = p;
> + return 1;
> + }
> + }
> +
> + p = (usb_ups_t*)privdata;
> +
> + if (NULL!=p)
> + {
> + if ( (p->vid==d->VendorID) && (p->pid==d->ProductID) )
> + {
> + usb_ups_device = p;
> + return 1;
> + }
> + }
> +
> + return 0;
> + }
> +
> + static int comm_usb_open(const char *param)
> + {
> + HIDDeviceMatcher_t match;
> + static usb_ups_t param_arg;
> + const char* p;
> + int ret,i;
> + union _u {
> + unsigned char report_desc[4096];
> + char flush_buf[256];
> + } u;
> + upsdebugx(4, "comm_usb_open");
> + memset(&match,0,sizeof(match));
> + match.match_function = &comm_usb_match;
> +
> + if (0!=strcmp(param,"auto"))
> + {
> + param_arg.vid = (uint16_t) strtoul(param,NULL,16);
> + p = strchr(param,':');
> + if (NULL!=p)
> + {
> + param_arg.pid = (uint16_t) strtoul(p+1,NULL,16);
> + } else {
> + param_arg.vid = 0;
> + }
> +
> + // pure heuristics - assume this unknown device speaks
> agiler protocol
> + param_arg.get_data = usb_ups_device->get_data;
> + param_arg.set_data = usb_ups_device->set_data;
> +
> + if (0!=param_arg.vid)
> + {
> + match.privdata = ¶m_arg;
> + } else {
> + upslogx(LOG_ERR,
> + "comm_usb_open: invalid usb device specified, must
> be \"auto\" or \"vid:pid\"");
> + return -1;
> + }
> + }
> +
> + ret = usb->open(&udev,&hiddevice,&match,u.report_desc,MODE_OPEN);
> + if (ret<0)
> + return ret;
> +
> + // flush input buffers
> + for (i=0;i<10;i++)
> + {
> + upsdebugx(4, "comm_usb_open: Flush buffers");
> + if (comm_usb_recv(u.flush_buf,sizeof(u.flush_buf),0,NULL)<1) break;
> + }
> + return 0;
> + }
> +
> + static void comm_usb_close(const char *param)
> + {
> + upsdebugx(4, "comm_usb_close");
> + usb->close(udev);
> + }
> +
> + static int comm_usb_send(const char *fmt,...)
> + {
> + char buf[128];
> + size_t len;
> + va_list ap;
> + upsdebugx(4, "comm_usb_send: Starting");
> + if (NULL==udev)
> + return -1;
> + va_start(ap, fmt);
> + len = vsnprintf(buf, sizeof(buf), fmt, ap);
> + va_end(ap);
> + if ((len < 1) || (len >= (int) sizeof(buf)))
> + {
> + upsdebugx(4, "in if test");
> + upslogx(LOG_WARNING, "comm_usb_send: vsnprintf needed more "
> + "than %d bytes", (int)sizeof(buf));
> + buf[sizeof(buf)-1]=0;
> + }
> + upsdebugx(4, "comm_usb_send: About to return");
> + return usb_ups_device->set_data(buf);
> + }
> +
> + static int comm_usb_recv(char *buffer,size_t buffer_len,char
> endchar,const char *ignchars)
> + {
> + int len;
> + char *src,*dst,c;
> +
> + upsdebugx(4, "comm_usb_recv: Starting");
> + if (NULL==udev)
> + return -1;
> +
> + len = usb_ups_device->get_data(buffer,buffer_len);
> + upsdebugx(4, "comm_usb_recv: len: %i", len);
> + if (len<0)
> + return len;
> +
> + dst = buffer;
> +
> + for (src=buffer;src!=(buffer+len);src++)
> + {
> + c = *src;
> + if ( (c==endchar) || (c==0) ) {
> + break;
> + }
> + if (ignchars == NULL) break;
> + if (NULL!=strchr(ignchars,c)) continue;
> + *(dst++) = c;
> + }
> +
> + // terminate string if we have space
> + if (dst!=(buffer+len))
> + {
> + *dst = 0;
> + }
> +
> + return (dst-buffer);
> + }
> +
> + static megatec_comm_t comm_usb =
> + {
> + .name = "usb",
> + .open = &comm_usb_open,
> + .close = &comm_usb_close,
> + .send = &comm_usb_send,
> + .recv = &comm_usb_recv
> + };
> +
> + megatec_comm_t *comm = & comm_usb;
> +
> +
> + /************** minidrivers go after this point **************************/
> +
> +
> + /*
> + Agiler seraial-to-usb device.
> +
> + Protocol was reverse-engineered from Windows driver
> + HID tables are complitely bogus
> + Data is transferred out as one 8-byte packet with report ID 0
> + Data comes in as 6 8-byte reports per line , padded with zeroes
> + All constants are hardcoded in windows driver
> + */
> +
> + #define AGILER_REPORT_SIZE 8
> + #define AGILER_REPORT_COUNT 6
> + #define AGILER_TIMEOUT 5000
> +
> + static int set_data_agiler(const char *str)
> + {
> + unsigned char report_buf[AGILER_REPORT_SIZE];
> +
> + if (strlen(str)>AGILER_REPORT_SIZE)
> + {
> + upslogx(LOG_ERR,
> + "set_data_agiler: output string too large");
> + return -1;
> + }
> +
> + memset(report_buf,0,sizeof(report_buf));
> + memcpy(report_buf,str,strlen(str));
> +
> + return usb->set_report(udev,0,report_buf,sizeof(report_buf));
> + }
> +
> + static int get_data_agiler(char *buffer,int buffer_size)
> + {
> + int i,len;
> + char buf[AGILER_REPORT_SIZE*AGILER_REPORT_COUNT+1];
> +
> + memset(buf,0,sizeof(buf));
> +
> + for (i=0;i<AGILER_REPORT_COUNT;i++)
> + {
> + len = usb->get_interrupt(udev,(unsigned char
> *)buf+i*AGILER_REPORT_SIZE,AGILER_REPORT_SIZE,AGILER_TIMEOUT);
> + if (len!=AGILER_REPORT_SIZE) {
> + if (len<0) len=0;
> + buf[i*AGILER_REPORT_SIZE+len]=0;
> + break;
> + }
> + }
> +
> + len = strlen(buf);
> +
> + if (len > buffer_size)
> + {
> + upslogx(LOG_ERR,
> + "get_data_agiler: input buffer too small");
> + len = buffer_size;
> + }
> +
> + memcpy(buffer,buf,len);
> + return len;
> + }
> +
> + /*
> + Ablerex seraial-to-usb device.
> +
> + Protocol was reverse-engineered from Windows driver
> + HID tables are complitely bogus
> + Data is transferred out as one 8-byte packet with report ID 0
> + Data comes in as 1 47-byte report per line , padded with zeroes
> + All constants are hardcoded in windows driver
> + */
> +
> + #define ABLEREX_REPORT_SIZE 47
> + #define ABLEREX_REPORT_COUNT 1
> + #define ABLEREX_TIMEOUT 5000
> + #define ABLEREX_RESPONSE_SIZE 11
> +
> + static char ablerex_response[ABLEREX_REPORT_SIZE];
> + static bool get_done;
> +
> + static int set_data_ablerex(const char *str)
> + {
> + char report_buf[ABLEREX_REPORT_SIZE];
> + int rc;
> + upsdebugx(4, "set_data_ablerex: Starting");
> + if (strlen(str)>ABLEREX_REPORT_SIZE)
> + {
> + upslogx(LOG_ERR,
> + "set_data_ablerex: output string too large");
> + return -1;
> + }
> +
> + memset(report_buf,0,sizeof(report_buf));
> + memcpy(report_buf,str,strlen(str));
> +
> + if (strcmp(str, "Q1\r") == 0)
> + {
> + upsdebugx(4, "set_data_ablerex: Doing Q1 stuff");
> + rc = usb_get_string_simple(udev, 3, report_buf, sizeof(report_buf));
> + get_done = TRUE;
> + }
> + else if (strcmp(str, "Q\r") == 0)
> + {
> + upsdebugx(4, "set_data_ablerex: Doing Q stuff");
> + rc = usb_get_string_simple(udev, 7, report_buf, sizeof(report_buf));
> + get_done = TRUE;
> + }
> + else if (strcmp(str, "C\r") == 0)
> + {
> + upsdebugx(4, "set_data_ablerex: Doing C stuff");
> + rc = usb_get_string_simple(udev, 11, report_buf, sizeof(report_buf));
> + get_done = TRUE;
> + }
> + else if (strcmp(str, "T\r") == 0)
> + {
> + upsdebugx(4, "set_data_ablerex: Doing T stuff");
> + rc = usb_get_string_simple(udev, 4, report_buf, sizeof(report_buf));
> + get_done = TRUE;
> + }
> + else if (strcmp(str, "I\r") == 0)
> + {
> + char rep1[sizeof(report_buf)], rep2[sizeof(report_buf)];
> + int rc1, rc2;
> + upsdebugx(4, "set_data_ablerex: Doing I stuff");
> + rc1 = usb_get_string_simple(udev, 1, rep1, sizeof(report_buf));
> + rc2 = usb_get_string_simple(udev, 2, rep2, sizeof(report_buf));
> + rc = rc1 + rc2;
> + strcpy(report_buf, rep1);
> + strcat(report_buf, rep2);
> + get_done = TRUE;
> + }
> + else if (strcmp(str, "F\r") == 0)
> + {
> + upsdebugx(4, "set_data_ablerex: Doing F stuff");
> + rc = usb_get_string_simple(udev, 13, report_buf, sizeof(report_buf));
> + get_done = TRUE;
> + }
> +
> + else
> + {
> + upsdebugx(4, "set_data_ablerex: doing set-report stuff");
> + rc = usb->set_report(udev,0, (unsigned char *)report_buf,
> strlen(report_buf));
> + get_done = FALSE;
> + }
> + strcpy(ablerex_response, report_buf);
> + upsdebugx(4, "set_data_ablerex: rc: %i, report_buf: %s", rc, report_buf);
> + return rc;
> + }
> +
> + static int get_data_ablerex(char *buffer,int buffer_size)
> + {
> + int i,len, rc;
> + char buf[ABLEREX_REPORT_SIZE*ABLEREX_REPORT_COUNT+1];
> +
> + upsdebugx(4, "get_data_ablerex: Starting");
> + // code to handle having issued and received response in set_data_ablerex
> + memset(buffer,0, buffer_size);
> + if (get_done == TRUE)
> + {
> + memcpy(buffer, ablerex_response, strlen(ablerex_response));
> + return strlen(ablerex_response);
> + }
> +
> + for (i=0;i<ABLEREX_REPORT_COUNT;i++)
> + {
> + len = usb->get_interrupt(udev, (unsigned char *)
> buf+i*ABLEREX_REPORT_SIZE,ABLEREX_REPORT_SIZE,ABLEREX_TIMEOUT);
> + upsdebugx(4, "get_data_ablerex: len: %i, error: %i, %s:
> buf: %s", len, errno, strerror(errno), buf);
> + if (len!=ABLEREX_REPORT_SIZE) {
> + if (len<0) len=0;
> + buf[i*ABLEREX_REPORT_SIZE+len]=0;
> + break;
> + }
> + }
> + len = strlen(buf);
> +
> + if (len > buffer_size)
> + {
> + upslogx(LOG_ERR,
> + "get_data_ablerex: input buffer too small");
> + len = buffer_size;
> + }
> +
> + upsdebugx(4, "get_data_ablerex: Leaving get_data_ablerex: len: %i", len);
> + memcpy(buffer,buf,len);
> + return len;
> + }
> +
> + /* EOF - megatec_usb.c */
More information about the Nut-upsdev
mailing list