---------- Forwarded Message ----------
Subject: [PATCH] New to nut project
Date: Friday, 6. November 2009
From: Patrick Levesque <[email protected]>
To: Thomas Jarosch <[email protected]>
As requested, here is my patch file including all my modification to the
2.4.1
tarball from the web site.
On Friday 06 November 2009 05:41:29 you wrote:
> Hello Patrick,
>
> On Wednesday, 4. November 2009 14:12:09 Levesque, Patrick wrote:
> > I have tried to support a TrippLite Internet350SER UPS using a serial
> > cable (The only connection on this model) using the 2.4 code branch. It
> > uses the Protocol 1004 from the tripplite specification that can be use
> > either used on serial or USB device. Since my device was only serial, I
> > worked only on the serial integration. Since I found nothing in
> > tripplite.c, tripplite-hid.c, tripplitesu.c to support my model, I have
> > done trippliteser.c in order to support my unit. Not all the
> > functionality are there but the core functionality is there. Since it
> > is licence as GPLv2, I just want to push back my modifs to the community
> > but really don't know the procedure.
>
> Do you know how diff/patch works? Just send your changes
> as unified diff (diff -u) to the devel list. Might be a good
> idea to prefix your mail subject with "[PATCH]".
>
> If possible, try to prevent winmail.dat attachments on the mailing list,
> so people with a normal email client can open the attachment.
>
> Cheers,
> Thomas
diff -crBN a/data/driver.list b/data/driver.list
*** a/data/driver.list 2009-02-17 04:20:45.000000000 -0500
--- b/data/driver.list 2009-09-01 13:53:08.000000000 -0400
***************
*** 627,632 ****
--- 627,633 ----
"Tripp-Lite" "AVR750U" "USB" "usbhid-ups"
"Tripp-Lite" "SmartOnline SU1500RTXL2ua" "USB" "usbhid-ups"
"Tripp-Lite" "smart2200RMXL2U" "USB, newer models" "usbhid-ups"
+ "Tripp-Lite" "INTERNET350SER" "" "trippliteser"
"Trust" "UPS 1000 Management PW-4105" "" "megatec"
"Trust" "UPS 1200VA Management PW-4120M" "" "megatec"
diff -crBN a/drivers/genericups.c b/drivers/genericups.c
*** a/drivers/genericups.c 2009-02-17 04:20:48.000000000 -0500
--- b/drivers/genericups.c 2009-10-16 15:06:42.000000000 -0400
***************
*** 66,71 ****
--- 66,74 ----
if (strstr(value, "RNG")) {
fatalx(EXIT_FAILURE, "Can't override output with RNG (not an output)");
}
+ if (strstr(value, "DSR")) {
+ fatalx(EXIT_FAILURE, "Can't override output with DSR (not an output)");
+ }
}
static void parse_input_signals(const char *value, int *line, int *val)
***************
*** 98,103 ****
--- 101,113 ----
*val |= TIOCM_RNG;
}
}
+ if (strstr(value, "DSR")) {
+ *line |= TIOCM_DSR;
+
+ if (!strstr(value, "-DSR")) {
+ *val |= TIOCM_DSR;
+ }
+ }
if (strstr(value, "DTR")) {
fatalx(EXIT_FAILURE, "Can't override input with DTR (not an input)");
diff -crBN a/drivers/Makefile.in b/drivers/Makefile.in
*** a/drivers/Makefile.in 2009-02-17 04:24:10.000000000 -0500
--- b/drivers/Makefile.in 2009-10-16 15:07:30.000000000 -0400
***************
*** 110,116 ****
newmge-shut$(EXEEXT) oneac$(EXEEXT) optiups$(EXEEXT) \
powercom$(EXEEXT) rhino$(EXEEXT) safenet$(EXEEXT) \
skel$(EXEEXT) solis$(EXEEXT) tripplite$(EXEEXT) \
! tripplitesu$(EXEEXT) upscode2$(EXEEXT) victronups$(EXEEXT) \
powerpanel$(EXEEXT) blazer_ser$(EXEEXT)
am__EXEEXT_2 = snmp-ups$(EXEEXT)
am__EXEEXT_3 = usbhid-ups$(EXEEXT) bcmxcp_usb$(EXEEXT) \
--- 110,116 ----
newmge-shut$(EXEEXT) oneac$(EXEEXT) optiups$(EXEEXT) \
powercom$(EXEEXT) rhino$(EXEEXT) safenet$(EXEEXT) \
skel$(EXEEXT) solis$(EXEEXT) tripplite$(EXEEXT) \
! tripplitesu$(EXEEXT) trippliteser$(EXEEXT) upscode2$(EXEEXT) victronups$(EXEEXT) \
powerpanel$(EXEEXT) blazer_ser$(EXEEXT)
am__EXEEXT_2 = snmp-ups$(EXEEXT)
am__EXEEXT_3 = usbhid-ups$(EXEEXT) bcmxcp_usb$(EXEEXT) \
***************
*** 334,339 ****
--- 334,343 ----
tripplitesu_OBJECTS = $(am_tripplitesu_OBJECTS)
tripplitesu_LDADD = $(LDADD)
tripplitesu_DEPENDENCIES = $(am__DEPENDENCIES_2)
+ am_trippliteser_OBJECTS = trippliteser.$(OBJEXT)
+ trippliteser_OBJECTS = $(am_trippliteser_OBJECTS)
+ trippliteser_LDADD = $(LDADD)
+ trippliteser_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_upscode2_OBJECTS = upscode2.$(OBJEXT)
upscode2_OBJECTS = $(am_upscode2_OBJECTS)
upscode2_DEPENDENCIES = $(am__DEPENDENCIES_3)
***************
*** 381,387 ****
$(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \
$(safenet_SOURCES) $(skel_SOURCES) $(snmp_ups_SOURCES) \
$(solis_SOURCES) $(tripplite_SOURCES) $(tripplite_usb_SOURCES) \
! $(tripplitesu_SOURCES) $(upscode2_SOURCES) \
$(upsdrvctl_SOURCES) $(usbhid_ups_SOURCES) \
$(victronups_SOURCES)
DIST_SOURCES = $(libdummy_a_SOURCES) $(libnuthalmain_a_SOURCES) \
--- 385,393 ----
$(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \
$(safenet_SOURCES) $(skel_SOURCES) $(snmp_ups_SOURCES) \
$(solis_SOURCES) $(tripplite_SOURCES) $(tripplite_usb_SOURCES) \
! $(tripplitesu_SOURCES) \
! $(trippliteser_SOURCES) \
! $(upscode2_SOURCES) \
$(upsdrvctl_SOURCES) $(usbhid_ups_SOURCES) \
$(victronups_SOURCES)
DIST_SOURCES = $(libdummy_a_SOURCES) $(libnuthalmain_a_SOURCES) \
***************
*** 403,409 ****
$(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \
$(safenet_SOURCES) $(skel_SOURCES) $(snmp_ups_SOURCES) \
$(solis_SOURCES) $(tripplite_SOURCES) $(tripplite_usb_SOURCES) \
! $(tripplitesu_SOURCES) $(upscode2_SOURCES) \
$(upsdrvctl_SOURCES) $(usbhid_ups_SOURCES) \
$(victronups_SOURCES)
HEADERS = $(dist_noinst_HEADERS)
--- 409,417 ----
$(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \
$(safenet_SOURCES) $(skel_SOURCES) $(snmp_ups_SOURCES) \
$(solis_SOURCES) $(tripplite_SOURCES) $(tripplite_usb_SOURCES) \
! $(tripplitesu_SOURCES) \
! $(trippliteser_SOURCES) \
! $(upscode2_SOURCES) \
$(upsdrvctl_SOURCES) $(usbhid_ups_SOURCES) \
$(victronups_SOURCES)
HEADERS = $(dist_noinst_HEADERS)
***************
*** 580,586 ****
bestuferrups bestups cyberpower dummy-ups etapro everups \
gamatronic genericups isbmex liebert masterguard megatec metasys \
mge-shut mge-utalk microdowell newmge-shut oneac optiups powercom rhino \
! safenet skel solis tripplite tripplitesu upscode2 victronups powerpanel \
blazer_ser
SNMP_DRIVERLIST = snmp-ups
--- 588,594 ----
bestuferrups bestups cyberpower dummy-ups etapro everups \
gamatronic genericups isbmex liebert masterguard megatec metasys \
mge-shut mge-utalk microdowell newmge-shut oneac optiups powercom rhino \
! safenet skel solis tripplite tripplitesu trippliteser upscode2 victronups powerpanel \
blazer_ser
SNMP_DRIVERLIST = snmp-ups
***************
*** 638,643 ****
--- 646,652 ----
tripplite_SOURCES = tripplite.c
tripplite_LDADD = $(LDADD) -lm
tripplitesu_SOURCES = tripplitesu.c
+ trippliteser_SOURCES = trippliteser.c
upscode2_SOURCES = upscode2.c
upscode2_LDADD = $(LDADD) -lm
victronups_SOURCES = victronups.c
***************
*** 964,969 ****
--- 973,981 ----
tripplitesu$(EXEEXT): $(tripplitesu_OBJECTS) $(tripplitesu_DEPENDENCIES)
@rm -f tripplitesu$(EXEEXT)
$(LINK) $(tripplitesu_OBJECTS) $(tripplitesu_LDADD) $(LIBS)
+ trippliteser$(EXEEXT): $(trippliteser_OBJECTS) $(trippliteser_DEPENDENCIES)
+ @rm -f trippliteser$(EXEEXT)
+ $(LINK) $(trippliteser_OBJECTS) $(trippliteser_LDADD) $(LIBS)
upscode2$(EXEEXT): $(upscode2_OBJECTS) $(upscode2_DEPENDENCIES)
@rm -f upscode2$(EXEEXT)
$(LINK) $(upscode2_OBJECTS) $(upscode2_LDADD) $(LIBS)
***************
*** 1055,1060 ****
--- 1067,1073 ----
@AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/tripplite...@am__quote@
@AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/tripplite_usb...@am__quote@
@AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/tripplitesu...@am__quote@
+ @AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/trippliteser...@am__quote@
@AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/upscode2...@am__quote@
@AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/upsdrvctl...@am__quote@
@AMDEP_TRUE@@am__include@ @am__qu...@./$(DEPDIR)/usb-common...@am__quote@
diff -crBN a/drivers/trippliteser.c b/drivers/trippliteser.c
*** a/drivers/trippliteser.c 1969-12-31 19:00:00.000000000 -0500
--- b/drivers/trippliteser.c 2009-11-02 16:42:52.000000000 -0500
***************
*** 0 ****
--- 1,641 ----
+ /* trippliteser.c - model specific routines for
+ Tripp Lite INTERNET (SER) models running protocol 1004
+
+ Copyright (C) 2009 Patrick Levesque <[email protected]>
+
+ 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
+ */
+
+ /* Notes:
+
+ The following parameters (ups.conf) are supported:
+ lowbatt
+
+ The following variables are supported (RW = read/write):
+ ambient.humidity (1)
+ ambient.temperature (1)
+ battery.charge
+ battery.current (1)
+ battery.temperature
+ battery.voltage
+ battery.voltage.nominal
+ driver.version.internal
+ input.frequency
+ input.sensitivity (RW) (1)
+ input.transfer.high (RW)
+ input.transfer.low (RW)
+ input.voltage
+ input.voltage.nominal
+ output.current (1)
+ output.frequency
+ output.voltage
+ output.voltage.nominal
+ ups.firmware
+ ups.id (RW) (1)
+ ups.load
+ ups.mfr
+ ups.model
+ ups.status
+ ups.test.result
+ ups.contacts (1)
+
+ The following instant commands are supported:
+ load.off
+ load.on
+ shutdown.reboot
+ shutdown.reboot.graceful
+ shutdown.return
+ shutdown.stop
+ test.battery.start
+ test.battery.stop
+
+ The following ups.status values are supported:
+ BOOST (1)
+ BYPASS
+ LB
+ OB
+ OFF
+ OL
+ OVER (2)
+ RB (2)
+ TRIM (1)
+
+ (1) these items have not been tested because they are not supported
+ by my SU1000RT2U.
+ (2) these items have not been tested because I haven't tested them.
+ */
+
+
+ #include "main.h"
+ #include "serial.h"
+
+ #define DRIVER_NAME "Tripp Lite INTERNET SER driver"
+ #define DRIVER_VERSION "0.01"
+
+ #define ENDCHAR '\r'
+ #define IGNCHAR 'X'
+
+ /* driver description structure */
+ upsdrv_info_t upsdrv_info = {
+ DRIVER_NAME,
+ DRIVER_VERSION,
+ "Patrick Levesque <[email protected]>",
+ DRV_EXPERIMENTAL,
+ { NULL }
+ };
+
+ #define MAX_RESPONSE_LENGTH 8
+ #define MAX_IDNETIFICATION_LENGTH 40
+
+ #define DEFAULT_OFFDELAY 64 /*!< seconds (max 2^16) */
+
+ static int battery_voltage_nominal = 0,
+ input_voltage_nominal = 0,
+ switchable_load_banks = 0;
+
+ /*! Time in seconds to delay before shutting down. */
+ static unsigned int offdelay = DEFAULT_OFFDELAY;
+ #if 0
+ static const char *test_result_names[] = {
+ "No test performed",
+ "Passed",
+ "In progress",
+ "General test failed",
+ "Battery failed",
+ "Deep battery test failed",
+ "Aborted"
+ };
+ #endif
+
+ # if 0
+ static struct {
+ int code;
+ const char *name;
+ } sensitivity[] = {
+ {0, "Normal"},
+ {1, "Reduced"},
+ {2, "Low"}
+ };
+ #endif
+
+ static struct {
+ int outlet_banks;
+ unsigned long commands_available;
+ } ups;
+
+
+ struct proto {
+ char command;
+ size_t req_size;
+ int csum;
+ size_t ans_size;
+ };
+
+ static struct proto proto_table[] =
+ {
+ /* Control value */
+ {'C', 4, 1, 2},
+ {'G', 4, 1, 2},
+ {'N', 6, 1, 2},
+ {'I', 5, 1, 2},
+ {'W', 5, 1, 3},
+ /* Command value */
+ {'\0', 4, 1, 8},
+ {'F', 4, 1, 8},
+ {'L', 4, 1, 6},
+ {'P', 4, 1, 8},
+ {'S', 4, 1, 5},
+ {'V', 4, 1, 8},
+ /* Unit identification */
+ {'1', 3, 0, 8},
+ {'2', 3, 0, 8},
+ {'3', 3, 0, 8},
+ {'4', 3, 0, 8},
+ {'5', 3, 0, 8},
+ {'6', 3, 0, 8},
+ };
+
+
+ #define DEFAULT_RESPONSE_LENGTH 8
+
+ /* index of the proto table */
+
+ enum trippliteser_command
+ {
+ /* Controls */
+ CANCEL_SHUTDOWN=0,
+ SHUTDOWN,
+ SET_PREDELAY,
+ SET_STATUS_FLAGS,
+ WATCHDOG,
+ /* Commands */
+ PROTOCOL,
+ uC_FIRMWARE,
+ STATUS_FLAGS,
+ POWER_RATING,
+ STATUS,
+ MODEL_VERSION,
+ /* Unit Identification */
+ IDENTIFICATION_1,
+ IDENTIFICATION_2,
+ IDENTIFICATION_3,
+ IDENTIFICATION_4,
+ IDENTIFICATION_5,
+ IDENTIFICATION_6
+ };
+
+ /*...@brief Convert N characters from hex to decimal
+ *
+ * @param start Beginning of string to convert
+ * @param len Maximum number of characters to consider (max 32)
+ *
+ * @a len characters of @a start are copied to a temporary buffer, then passed
+ * to strtol() to be converted to decimal.
+ *
+ * @return See strtol(3)
+ */
+ static int hex2d(const unsigned char *start, unsigned int len)
+ {
+ unsigned char buf[32];
+ buf[31] = '\0';
+
+ strncpy((char *)buf, (char *)start, (len < (sizeof buf) ? len : (sizeof buf - 1)));
+ if(len < sizeof(buf)) buf[len] = '\0';
+ return strtol((char *)buf, NULL, 16);
+ }
+
+ void decode_v(const unsigned char *value)
+ {
+ unsigned char ivn, lb;
+ int bv = hex2d(value+2, 2);
+
+ ivn = value[1];
+ lb = value[4];
+
+ switch(ivn) {
+ case '0': input_voltage_nominal = 100;
+ break;
+ case '1': input_voltage_nominal = 120;
+ break;
+ case '2': input_voltage_nominal = 208;
+ break;
+ case '3': input_voltage_nominal = 230;
+ break;
+ case '4': input_voltage_nominal = 240;
+ break;
+ default:
+ upslogx(2, "Unknown input voltage range: 0x%02x", (unsigned int)ivn);
+ break;
+ }
+
+ battery_voltage_nominal = bv * 6;
+
+ if( (lb >= '0') && (lb <= '9') ) {
+ switchable_load_banks = lb - '0';
+ } else {
+ if( lb != 'X' ) {
+ upslogx(2, "Unknown number of switchable load banks: 0x%02x",
+ (unsigned int)lb);
+ }
+ }
+ }
+
+ static int do_command(enum trippliteser_command command, unsigned char *msg, size_t msg_len, unsigned char *reply, size_t reply_len)
+ {
+ unsigned char buffer[MAX_RESPONSE_LENGTH];
+ unsigned int i = 0, csum = 0;
+ int ret;
+
+ ser_flush_io(upsfd);
+
+ if (reply_len < MAX_RESPONSE_LENGTH) {
+ upsdebugx(3, "do_command: reply do not have minimum size of 8 bytes!");
+ return -1;
+ }
+
+ if (reply) {
+ memset(reply, 0, reply_len);
+ }
+
+ upsdebugx(3, "Performing command %c [0x%02x] with request size %d and answer size %d\n", proto_table[command].command, proto_table[command].command, proto_table[command].req_size, proto_table[command].ans_size);
+ memset(buffer, 0, sizeof(buffer));
+
+ /* Now fill the buffer */
+ buffer[0] = ':';
+
+ buffer[1] = proto_table[command].command;
+
+ if (proto_table[command].csum) {
+ csum = proto_table[command].command;
+
+ /* skip : and remove ENDCHAR from the csum computation */
+ for(i=0; i<msg_len; i++) {
+ buffer[i+2] = msg[i];
+ csum += msg[i];
+ }
+ buffer[i+2] = 255-csum;
+ i++;
+ }
+ buffer[i+2] = ENDCHAR;
+
+ ret = ser_send_buf_pace(upsfd, 0, buffer, proto_table[command].req_size);
+ if (ret <= 0) {
+ upsdebug_with_errno(3, "do_command: send [%s]", buffer);
+ return -1;
+ }
+
+ upsdebugx(3, "do_command: %d bytes sent [0x%02x%02x%02x%02x] 0x%02x -> OK", ret, buffer[0], buffer[1], buffer[2], buffer[3], '\r');
+
+ ret = ser_get_buf_len(upsfd, reply, proto_table[command].ans_size, 3, 0);
+ if (ret < 0) {
+ upsdebug_with_errno(3, "do_command: read");
+ return -1;
+ }
+ if (ret == 0) {
+ upsdebugx(3, "do_command: read -> TIMEOUT");
+ return -1;
+ }
+
+ upsdebugx(3, "do_command: %d byted read 0x%02x%02x%02x%02x%02x%02x%02x%02x", ret, reply[0], reply[1],reply[2],reply[3],reply[4],reply[5],reply[6],reply[7]);
+
+ if (reply[0] != proto_table[command].command) {
+ upsdebugx(3, "do_command: response not expected!");
+ return -1;
+ }
+ return ret;
+ }
+
+ static int do_productName(char *productName, size_t productName_len)
+ {
+ unsigned char response[MAX_RESPONSE_LENGTH];
+ unsigned int len = 0;
+ int i = 0, j = 0;
+
+ if (productName == NULL) {
+ upsdebugx(3, "%s: input buffer is null!", __FUNCTION__);
+ return -1;
+ }
+ memset(productName, 0, productName_len);
+ len = 0;
+
+ if (do_command(IDENTIFICATION_2, NULL, 0, response, sizeof(response)) <= 0) {
+ upsdebugx(3, "IDENTIFICATION_2 failed\n");
+ return -1;
+ }
+ for (j=1;response[j] != '\r' && j < MAX_RESPONSE_LENGTH; i++, j++) {
+ productName[i] = response[j];
+ len++;
+ }
+ if (do_command(IDENTIFICATION_3, NULL, 0, response, sizeof(response)) <= 0) {
+ upsdebugx(3, "IDENTIFICATION_3 failed\n");
+ return -1;
+ }
+ for (j=1;response[j] != '\r' && j < MAX_RESPONSE_LENGTH; i++, j++) {
+ productName[i] = response[j];
+ len++;
+ }
+ if (do_command(IDENTIFICATION_4, NULL, 0, response, sizeof(response)) <= 0) {
+ upsdebugx(3, "IDENTIFICATION_4 failed\n");
+ return -1;
+ }
+ for (j=1;response[j] != '\r' && j < MAX_RESPONSE_LENGTH; i++, j++) {
+ productName[i] = response[j];
+ len++;
+ }
+ if (do_command(IDENTIFICATION_5, NULL, 0, response, sizeof(response)) <= 0) {
+ upsdebugx(3, "IDENTIFICATION_5 failed\n");
+ return -1;
+ }
+ for (j=1;response[j] != '\r' && j < MAX_RESPONSE_LENGTH; i++, j++) {
+ productName[i] = response[j];
+ len++;
+ }
+ if (do_command(IDENTIFICATION_6, NULL, 0, response, sizeof(response)) <= 0) {
+ upsdebugx(3, "IDENTIFICATION_6 failed\n");
+ return -1;
+ }
+ for (j=1;response[j] != '\r' && j < MAX_RESPONSE_LENGTH; i++, j++) {
+ productName[i] = response[j];
+ len++;
+ }
+ productName[i] = '\0';
+ len++;
+
+ /* Trim trailing spaces */
+ for(i--;productName[i] == ' ';i--) {
+ productName[i] = '\0';
+ len--;
+ }
+
+ upsdebugx(3, "Product Name so far %s of size %d\n", productName, len);
+
+ return len;
+ }
+
+ #if 0
+ static int get_identification(void) {
+ unsigned char response[MAX_RESPONSE_LENGTH];
+
+ if (do_command(IDENTIFICATION_2, NULL, 0, response, sizeof(response)) >= 0) {
+ dstate_setinfo("ups.id", "%s", response);
+ return 1;
+ }
+
+ return 0;
+ }
+ #endif
+ #if 0
+ static void set_identification(const char *val) {
+ char response[MAX_RESPONSE_LENGTH];
+
+ if (do_command(IDENTIFICATION, "", response) < 0)
+ return;
+ if (strcmp(val, response)) {
+ strncpy(response, val, MAX_RESPONSE_LENGTH);
+ response[MAX_RESPONSE_LENGTH - 1] = '\0';
+ do_command(IDENTIFICATION, response, NULL);
+ }
+ }
+ #endif
+
+ #if 0
+ static int get_transfer_voltage_low(void) {
+ char response[MAX_RESPONSE_LENGTH];
+ char *ptr;
+
+ if (do_command(TRANSFER_VOLTAGE, "", response) > 0) {
+ ptr = field(response, 0);
+ if (ptr)
+ dstate_setinfo("input.transfer.low", "%d", atoi(ptr));
+ return 1;
+ }
+
+ return 0;
+ }
+ #endif
+
+ static int instcmd(const char *cmdname, const char *extra)
+ {
+ #if 0
+ int i;
+
+ char parm[20];
+
+ if (!strcasecmp(cmdname, "load.off")) {
+ for (i = 0; i < ups.outlet_banks; i++) {
+ snprintf(parm, sizeof(parm), "%d;1", i + 1);
+ do_command(SET, RELAY_OFF, parm, NULL);
+ }
+ return STAT_INSTCMD_HANDLED;
+ }
+ if (!strcasecmp(cmdname, "load.on")) {
+ for (i = 0; i < ups.outlet_banks; i++) {
+ snprintf(parm, sizeof(parm), "%d;1", i + 1);
+ do_command(SET, RELAY_ON, parm, NULL);
+ }
+ return STAT_INSTCMD_HANDLED;
+ }
+ if (!strcasecmp(cmdname, "shutdown.reboot")) {
+ auto_reboot(1);
+ do_command(SET, SHUTDOWN_RESTART, "1", NULL);
+ do_command(SET, SHUTDOWN_ACTION, "10", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ if (!strcasecmp(cmdname, "shutdown.reboot.graceful")) {
+ auto_reboot(1);
+ do_command(SET, SHUTDOWN_RESTART, "1", NULL);
+ do_command(SET, SHUTDOWN_ACTION, "60", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ if (!strcasecmp(cmdname, "shutdown.return")) {
+ auto_reboot(1);
+ do_command(SET, SHUTDOWN_RESTART, "1", NULL);
+ do_command(SET, SHUTDOWN_ACTION, "10", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ #if 0 /* doesn't seem to work */
+ if (!strcasecmp(cmdname, "shutdown.stayoff")) {
+ auto_reboot(0);
+ do_command(SET, SHUTDOWN_ACTION, "10", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ #endif
+ if (!strcasecmp(cmdname, "shutdown.stop")) {
+ do_command(SET, SHUTDOWN_ACTION, "0", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ if (!strcasecmp(cmdname, "test.battery.start")) {
+ do_command(SET, TEST, "3", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ if (!strcasecmp(cmdname, "test.battery.stop")) {
+ do_command(SET, TEST, "0", NULL);
+ return STAT_INSTCMD_HANDLED;
+ }
+ upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
+ return STAT_INSTCMD_UNKNOWN;
+ #endif
+ return STAT_INSTCMD_HANDLED;
+ }
+
+
+ static int setvar(const char *varname, const char *val)
+ {
+ #if 0
+ if (!strcasecmp(varname, "ups.id")) {
+ set_identification(val);
+ get_identification();
+ return STAT_SET_HANDLED;
+ }
+ upslogx(LOG_NOTICE, "setvar: unknown var [%s]", varname);
+ #endif
+ return STAT_SET_UNKNOWN;
+ }
+
+
+ static int init_comm(void)
+ {
+ unsigned char response[MAX_RESPONSE_LENGTH];
+
+ ups.commands_available = 0;
+
+ if (do_command(PROTOCOL, NULL, 0, response, sizeof(response)) <= 0) {
+ return 0;
+ }
+
+ /* Make sure the control protocol is 0x1004 */
+ if (response[1] != 0x10 || response[2] != 0x04) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ void upsdrv_initinfo(void)
+ {
+ unsigned char response[MAX_RESPONSE_LENGTH];
+ char productName[MAX_IDNETIFICATION_LENGTH];
+ // unsigned int pre_delay, alarm;
+
+ if (!init_comm())
+ fatalx(EXIT_FAILURE, "Unable to detect Tripp Lite SmartOnline UPS on port %s\n",
+ device_path);
+ dstate_setinfo("ups.mfr", "%s", "Tripp Lite");
+ if (do_productName(productName, sizeof(productName)))
+ dstate_setinfo("ups.model", "%s", productName);
+ if (do_command(PROTOCOL, NULL, 0, response, sizeof(response)))
+ dstate_setinfo("ups.firmware.aux", "%02x%02x", response[1], response[2]);
+ if (do_command(uC_FIRMWARE, NULL, 0, response, sizeof(response)))
+ dstate_setinfo("ups.firmware", "69-%c%c%c%c Rev %c%c", response[1], response[2], response[3], response[4], response[5], response[6]);
+ if (do_command(MODEL_VERSION, NULL, 0, response, sizeof(response))) {
+ decode_v(response);
+ dstate_setinfo("input.voltage.nominal", "%d", input_voltage_nominal);
+ dstate_setinfo("battery.voltage.nominal", "%d", battery_voltage_nominal);
+ dstate_setinfo("ups.debug.load_banks", "%d", switchable_load_banks);
+ }
+
+ dstate_setinfo("ups.delay.shutdown", "%d", offdelay);
+ dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING);
+ dstate_setaux("ups.delay.shutdown", 3);
+
+ /* add all the variables that change regularly */
+ upsdrv_updateinfo();
+
+ upsh.instcmd = instcmd;
+ upsh.setvar = setvar;
+ }
+
+ void upsdrv_updateinfo(void)
+ {
+
+ unsigned char response[MAX_RESPONSE_LENGTH];
+
+ status_init();
+ if (do_command(STATUS, NULL, 0, response, sizeof(response)) <= 0) {
+ dstate_datastale();
+ return;
+ }
+
+ if (response[1] == '0') {
+ status_set("LB");
+ }
+
+ switch (response[2]) {
+ case '0':
+ status_set("OL");
+ break;
+ case '1':
+ status_set("OB");
+ break;
+ case '2':
+ status_set("CHRG");
+ break;
+ case '3':
+ status_set("IDLE");
+ break;
+ default:
+ break;
+ }
+
+ dstate_setinfo("battery.charge", "%d", response[3]);
+
+ /* if we are here, status is valid */
+ status_commit();
+ dstate_dataok();
+
+ }
+
+ void upsdrv_shutdown(void)
+ {
+ unsigned char response[MAX_RESPONSE_LENGTH];
+ unsigned char preDelay[2] = {0x00, 0x00};
+ upsdebugx(3, "upsdrv_shutdown is CALLED\n");
+ /* Make sure the system run on battery because the system will not be brought back in case the system is on line */
+ if (do_command(STATUS, NULL, 0, response, sizeof(response)) <= 0)
+ fatalx(EXIT_FAILURE, "Unable to get the line status!");
+
+ if (response[2] != '0' ) {
+ upsdebugx(3, "Performing the shutdown\n");
+ if (do_command(SET_PREDELAY, preDelay, sizeof(preDelay), response, sizeof(response)) <= 0)
+ upslogx(LOG_NOTICE, "SET_PREDELAY failed");
+ if (do_command(SHUTDOWN, NULL, 0, response, sizeof(response)) <= 0)
+ upslogx(LOG_NOTICE, "SHUTDOWN failed");
+ }
+ else
+ {
+ upsdebugx(3, "Shutdown bypass because we are on line\n");
+ }
+ }
+
+ void upsdrv_help(void)
+ {
+ }
+
+ /* list flags and values that you want to receive via -x or ups.conf */
+ void upsdrv_makevartable(void)
+ {
+ addvar(VAR_VALUE, "lowbatt", "Set low battery level, in percent");
+ }
+
+ 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);
+ }
_______________________________________________
Nut-upsdev mailing list
[email protected]
http://lists.alioth.debian.org/mailman/listinfo/nut-upsdev