[Bill: I think the list server didn't recognize your address below. Forwarding manually.]

From: Bill Elliot <[email protected]>
Subject: Initial review of ONEAC driver
Date: February 28, 2012 1:14:27 PM EST


At Arnaud's request, here is the 'svn di' patch for the Oneac driver and
man page.

The FSD status sending is controlled by the presence of a flag in
ups.conf.  The default is to NOT implement this behavior.

Looking forward to comments/feedback...be nice to the new guy!

Bill

Index: scripts/upower/95-upower-hid.rules
===================================================================
--- scripts/upower/95-upower-hid.rules	(revision 3468)
+++ scripts/upower/95-upower-hid.rules	(working copy)
@@ -18,7 +18,7 @@
 ATTRS{idVendor}=="050d", ENV{UPOWER_VENDOR}="Belkin"
 ATTRS{idVendor}=="051d", ENV{UPOWER_VENDOR}="APC"
 ATTRS{idVendor}=="0592", ENV{UPOWER_VENDOR}="Powerware"
-ATTRS{idVendor}=="06da", ENV{UPOWER_VENDOR}="Phoenixtec"
+ATTRS{idVendor}=="06da", ENV{UPOWER_VENDOR}="Phoenixtec Power Co., Ltd"
 ATTRS{idVendor}=="075d", ENV{UPOWER_VENDOR}="iDowell"
 ATTRS{idVendor}=="0764", ENV{UPOWER_VENDOR}="Cyber Power Systems"
 ATTRS{idVendor}=="09ae", ENV{UPOWER_VENDOR}="TrippLite"
@@ -58,7 +58,7 @@
 # Powerware
 ATTRS{idVendor}=="0592", ATTRS{idProduct}=="0004", ENV{UPOWER_BATTERY_TYPE}="ups"
 
-# Phoenixtec
+# Phoenixtec Power Co., Ltd
 ATTRS{idVendor}=="06da", ATTRS{idProduct}=="ffff", ENV{UPOWER_BATTERY_TYPE}="ups"
 
 # iDowell
Index: docs/man/oneac.txt
===================================================================
--- docs/man/oneac.txt	(revision 3468)
+++ docs/man/oneac.txt	(working copy)
@@ -15,9 +15,10 @@
 
 SUPPORTED HARDWARE
 ------------------
-This driver supports Oneac EG and ON UPS equipment with the
-Advanced Interface. If your UPS is equipped with the Basic
-Interface card, use the genericups driver.
+This driver supports Oneac EG and early ON UPS equipment with 
+the plug-in Advanced Interface and the later ON UPS equipment
+with the built-in DB-25 interface. If your UPS is equipped 
+with the Basic Interface card, use the genericups driver.
 
 EXTRA ARGUMENTS
 ---------------
@@ -27,27 +28,81 @@
 *testtime*='num'::
 Change battery test time from the 2 minute default.
 
+*shuttime*='num'::
+Change shutdown delay time from 0 second default.
+
+*FSDflag*::
+If this flag is present the FSD status will be sent
+whenever a UPS shutdown with delay becomes active.
+
 INSTANT COMMANDS
 ----------------
 This driver supports the following Instant Commands.
+(See linkman:upscmd[8])
 
-*reset.input.minmax*::
-Reset the minimum and maximum input line voltage values
-seen since the last reset or power on.
+All UPS units:
+*shutdown.return*::
+Turn off the load possibly after a delay and return when power is back.
 
-*test.battery.start*::
-Start a battery test.  The default time is 2 minutes.  This
-time can be set in the *ups.conf* file.  See *testime* above.
+*shutdown.stop*::
+Stop a shutdown in progress.
 
-*test.battery.stop*::
-Stops a battery test that is in progress.
+*shutdown.reboot*::
+Shut down the load briefly while rebooting the UPS.
 
 *test.failure.start*::
 Starts a 15 second long simulation of an input power
 failure.
 
+*test.battery.start.quick*::
+Start a "quick" battery test.  The default time is 2 minutes.  This
+time can be set in the *ups.conf* file.  See *testime* above.
+
+*test.battery.stop*::
+Stops a battery test that is in progress.
+
+All ON UPS units:
+*reset.input.minmax*::
+Reset the minimum and maximum input line voltage values
+seen since the last reset or power on.
+
+Newer ON UPS units:
+*test.panel.start*::
+Start testing the UPS panel.
+
+*test.battery.start.deep*::
+Start a "deep" battery test.  This test runs the UPS until the low
+battery point and then returns to the AC line.
+
+*reset.input.minmax*::
+Reset the minimum and maximum input line voltage values
+seen since the last reset or power on.
+
+*beeper.enable*::
+Enable UPS beeper/buzzer.
+
+*beeper.disable*::
+Disable UPS beeper/buzzer.
+
+*beeper.mute*::
+Mutes the UPS beeper/buzzer for the current alarm condition(s).
+
+Writable Variables
+------------------
+See linkman:upsrw[8] to see what variables are writable for the UPS.
+
+NOTE: If your UPS supports writing battery.runtime.low, the new set value
+is to be entered in minutes (up to 99) but the reported value is reported
+in seconds (set value * 60).
+
+NOTE: If your UPS supports input.transfer.low and input.transfer.high,
+those values are used to create an allowable output range.  The UPS 
+will do what it can to keep the output voltage value within the 
+defined range (for example: tap change or switch to inverter).
+
 AUTHOR
 ------
+Bill Elliot <[email protected]>
 Eric Lawson <[email protected]>
 
 SEE ALSO
Index: drivers/oneac.c
===================================================================
--- drivers/oneac.c	(revision 3468)
+++ drivers/oneac.c	(working copy)
@@ -1,13 +1,22 @@
 /*vim ts=4*/
 
-/*
- * NUT Oneac EG and ON model specific drivers for UPS units using
- * the Oneac Advanced Interface.  If your UPS is equipped with the
- * Oneac Basic Interface, use the genericups driver
+/* oneac-new.c
+ *
+ * NUT Oneac UPS driver for models using the Advanced Interface.
+ * If your UPS is equipped with the Oneac Basic Interface, use 
+ * the genericups driver.
+ *
+ * Supported Oneac UPS families in this driver:
+ * EG (late 80s, early 90s, plug-in serial interface card)
+ * ON (early and mid-90s, plug-in serial interface card)
+ * OZ (mid-90s on, DB-25 std., interface slot)
+ * OB (early 2000's on, big cabinet, DB-25 std., interface slot)
+ *
 */
 
 /*
    Copyright (C) 2003  by Eric Lawson <[email protected]>
+		(C) 2012 by Bill Elliot <[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
@@ -24,6 +33,11 @@
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
 
+/* 7 February 2012.  Bill Elliot
+ * Enhancing the driver for additional capabilities and later units.
+ *
+*/
+
 /* 28 November 2003.  Eric Lawson
  * More or less complete re-write for NUT 1.5.9 
  * This was somewhat easier than trying to beat the old driver code 
@@ -34,24 +48,77 @@
 #include "serial.h"
 #include "oneac.h"
 
-#define DRIVER_NAME	"Oneac EG/ON UPS driver"
-#define DRIVER_VERSION	"0.51"
+/* Prototypes to allow setting pointer before function is defined */
+int setcmd(const char* varname, const char* setvalue);
+int instcmd(const char *cmdname, const char *extra);
 
+#define DRIVER_NAME	"Oneac EG/ON/OZ/OB UPS driver"
+#define DRIVER_VERSION	"0.80"
+
 /* driver description structure */
 upsdrv_info_t upsdrv_info = {
 	DRIVER_NAME,
 	DRIVER_VERSION,
+	"Bill Elliot <[email protected]>\n"
 	"Eric Lawson <[email protected]>",
-	DRV_EXPERIMENTAL,
+	DRV_STABLE,
 	{ NULL }
 };
 
-#define SECS 2		/*wait time*/
-#define USEC 0		/*rest of wait time*/
+#define SECS 0			/* Serial function wait time*/
+#define USEC 500000		/* Rest of serial function wait time*/
 
+#define COMM_TRIES	3	/* Serial retries before "stale" */
+
+static char UpsFamily [3];
+
+/****************************************************************
+ * Below are functions used only in this oneac driver			*
+ ***************************************************************/
+
+/* Since an installed network card may delay responses from the UPS
+ *  allow for a repeat of the get request.  Also confirm that
+ *  the correct number of characters are returned.
+ */
+ 
+int OneacGetResponse (char* chBuff, const int BuffSize, int ExpectedCount)
+{
+int Retries = 10;			/* x/2 seconds max with 500000 USEC */
+int return_val;
+
+	do
+	{
+		return_val = ser_get_line(upsfd, chBuff, BuffSize, ENDCHAR, IGNCHARS, 
+																	SECS, USEC);
+
+		if (return_val == ExpectedCount)
+			break;
+
+		upsdebugx (3,"!OneacGetResponse retry (%d, %d)...", return_val,Retries);
+		
+	} while (--Retries > 0);
+
+	upsdebugx (4,"OneacGetResponse buffer: %s",chBuff);
+
+	if (Retries == 0)
+	{
+		upsdebugx (2,"!!OneacGetResponse timeout...");
+		return_val = 1;					/* Comms error */
+	}
+	else
+	{
+		if (Retries < 10)
+			upsdebugx (2,"OneacGetResponse recovered (%d)...", Retries);
+			
+		return_val = 0;					/* Good comms */
+	}
+	
+    return return_val;
+}
+
 void do_battery_test(void)
 {
-	char buffer[256];
+	char buffer[32];
 
 	if (getval("testtime") == NULL)
 		snprintf(buffer, 3, "%s", DEFAULT_BAT_TEST_TIME);
@@ -69,180 +136,424 @@
 	ser_send(upsfd,"%s%s%s",BAT_TEST_PREFIX,buffer,COMMAND_END);
 }
 
-
-/****************************************************************
- *below are the commands that are called by main (part of the   *
- *Above, are functions used only in this oneac driver           *
- ***************************************************************/
-
-int instcmd(const char *cmdname, const char *extra)
+int SetOutputAllow(const char* lowval, const char* highval)
 {
-	if (!strcasecmp(cmdname, "test.failure.start")) {
-		ser_send(upsfd,"%s%s",SIM_PWR_FAIL,COMMAND_END);
-		return STAT_INSTCMD_HANDLED;
-	}
+char buffer[32];
+ 		
+	snprintf(buffer, 4, "%.3s", lowval);
 
-	if (!strcasecmp(cmdname, "test.battery.start")) {
-		do_battery_test();
-		return STAT_INSTCMD_HANDLED;
+	/*the UPS wants this value to always be three characters long*/
+	/*so put a zero in front of the string, if needed....      */
+	
+	if (strlen(buffer) < 3)
+	{
+		buffer[3] = '\0';
+		buffer[2] = buffer[1];
+		buffer[1] = buffer[0];
+		buffer[0] = '0';
 	}
+	
+	upsdebugx (2,"SetOutputAllow sending %s%.3s,%.3s...", 
+											SETX_OUT_ALLOW, buffer, highval);
+					
+	ser_send(upsfd,"%s%.3s,%.3s%s", SETX_OUT_ALLOW, buffer, highval, 
+																COMMAND_END);
+	ser_get_line(upsfd,buffer,sizeof(buffer), ENDCHAR, IGNCHARS,SECS,USEC);
+	
+	if(buffer[0] == DONT_UNDERSTAND)
+	{
+		upsdebugx (2,"SetOutputAllow got asterisk back...");
 
-	if (!strcasecmp(cmdname, "test.battery.stop")) {
-		ser_send(upsfd,"%s00%s",BAT_TEST_PREFIX,COMMAND_END);
-		return STAT_INSTCMD_HANDLED;
+		return 1;					/* Invalid command */
 	}
+	
+	return 0;						/* Valid command */
+}
 
-	if (!strcasecmp(cmdname, "reset.input.minmax")) {
-		ser_send(upsfd,"%c%s",RESET_MIN_MAX, COMMAND_END);
-		return STAT_INSTCMD_HANDLED;
+void EliminateLeadingZeroes (const char* buff1, int StringSize, char* buff2, 
+															const int buff2size)
+{
+int i = 0;
+int j = 0;
+
+	memset(buff2, '\0', buff2size);			/* Fill with nulls */
+	
+	/* Find first non-'0' */
+	while ((buff1[i] == '0') && (i < (StringSize - 1)))
+	{
+		i++;
 	}
+	
+	while (i < StringSize)					/* Move rest of string */
+	{
+		buff2[j++] = buff1[i++];
+	}
+}
 
-	upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
-	return STAT_INSTCMD_UNKNOWN;
+
+/****************************************************************
+ * Below are the commands that are called by main				*
+ ***************************************************************/
+
+void upsdrv_initups(void)
+{
+	upsfd = ser_open(device_path);
+	ser_set_speed(upsfd, device_path, B9600);
+
+/*get the UPS in the right frame of mind*/
+	
+	ser_send_pace(upsfd, 100, "%s", COMMAND_END);
+	ser_send_pace(upsfd, 100, "%s", COMMAND_END);
+	sleep (1);
 }
 
-
 void upsdrv_initinfo(void)
 {
-	int i;
-	char buffer[256], buffer2[32];
+int i,j, k;
+int VRange=0;
+int timevalue;
+int RetValue;
+char buffer[256], buffer2[32];
+	
+	/* All families should reply to this request so we can confirm that it is
+	 *  an ONEAC UPS
+	 */
+	 
 	ser_flush_in(upsfd,"",0);
-	ser_send(upsfd,"%c%s",GET_MFR,COMMAND_END);
-	ser_get_line(upsfd, buffer, sizeof(buffer),ENDCHAR,IGNCHARS,SECS,USEC);
-	if(strncmp(buffer,MFGR, sizeof(MFGR)))
-		fatalx(EXIT_FAILURE, "Unable to connect to ONEAC UPS on %s\n",device_path);	
- 
-	dstate_setinfo("ups.mfr", "%s", buffer);
-	dstate_addcmd("test.battery.start");
+	ser_send(upsfd,"%c%s",GET_FAMILY,COMMAND_END);
+	
+	if(OneacGetResponse (buffer, sizeof(buffer), 2))
+	{
+		fatalx(EXIT_FAILURE, "Serial timeout with ONEAC UPS on %s\n",
+																device_path);
+	}
+	else
+	{
+		if (strncmp(buffer,FAMILY_ON,FAMILY_SIZE) != 0 && 
+			strncmp(buffer,FAMILY_OZ,FAMILY_SIZE) != 0 &&
+			strncmp(buffer,FAMILY_OB,FAMILY_SIZE) != 0 && 
+			strncmp(buffer,FAMILY_EG,FAMILY_SIZE) != 0)
+		{
+			fatalx(EXIT_FAILURE, "Did not find an ONEAC UPS on %s\n",
+																device_path);	
+		}
+	}
+
+	/*UPS Model (either EG, ON, OZ or OB series of UPS)*/
+	strncpy(UpsFamily, buffer, FAMILY_SIZE);
+	UpsFamily[2] = '\0';
+	dstate_setinfo("device.model", "%s",UpsFamily);
+	printf("Found %s family of Oneac UPS\n", UpsFamily);
+
+	dstate_setinfo("ups.type", "%s", "Line Interactive");
+	
+	dstate_addcmd("test.battery.start.quick");
 	dstate_addcmd("test.battery.stop");
 	dstate_addcmd("test.failure.start");
-	dstate_addcmd("reset.input.minmax");
+	dstate_addcmd("shutdown.return");
+	dstate_addcmd("shutdown.stop");
+	dstate_addcmd("shutdown.reboot");
 
-
+	upsh.setvar = setcmd;
 	upsh.instcmd = instcmd;
 
 	/*set some stuff that shouldn't change after initialization*/
-	/*this stuff is common to both the EG and ON family of UPS */
+	/*this stuff is common to all families of UPS */
 
+	ser_send(upsfd,"%c%s",GET_ALL,COMMAND_END);
+	
+	if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) == 0)
+	{
+		RetValue = OneacGetResponse (buffer, sizeof(buffer), 
+														GETALL_EG_RESP_SIZE);
+	}
+	else
+	{
+		RetValue = OneacGetResponse (buffer, sizeof(buffer), GETALL_RESP_SIZE);
+	}
+
+	if(RetValue)
+	{
+		fatalx(EXIT_FAILURE, "Serial timeout(2) with ONEAC UPS on %s\n",
+																device_path);
+	}
+	
+	/* Manufacturer */
+	dstate_setinfo("device.mfr", "%.5s", buffer);
+
 	/*firmware revision*/
-	ser_send(upsfd,"%c%s", GET_VERSION, COMMAND_END);
-	ser_get_line(upsfd, buffer, sizeof(buffer),ENDCHAR,IGNCHARS,SECS,USEC);
-	dstate_setinfo("ups.firmware", "%.3s",buffer);
+	dstate_setinfo("ups.firmware", "%.3s",buffer+7);
 
 	/*nominal AC frequency setting --either 50 or 60*/
-	ser_send(upsfd,"%c%s", GET_NOM_FREQ, COMMAND_END);
-	ser_get_line(upsfd,buffer,sizeof(buffer),ENDCHAR,IGNCHARS,SECS,USEC);
-	dstate_setinfo("input.frequency", "%.2s", buffer);
+	dstate_setinfo("input.frequency.nominal", "%.2s", buffer+20);
+	dstate_setinfo("output.frequency.nominal", "%.2s", buffer+20);
 
+	/* Shutdown delay in seconds...can be changed by user */
+	if (getval("shuttime") == NULL)
+		dstate_setinfo("ups.delay.shutdown", "0");
+	else
+		dstate_setinfo("ups.delay.shutdown", "%s", getval("shuttime"));
 
-	/*UPS Model (either ON, or EG series of UPS)*/
+	dstate_setflags("ups.delay.shutdown", ST_FLAG_STRING | ST_FLAG_RW);
+	dstate_setaux("ups.delay.shutdown", GET_SHUTDOWN_RESP_SIZE);
 	
-	ser_send(upsfd,"%c%s", GET_FAMILY,COMMAND_END);
-	ser_get_line(upsfd,buffer,sizeof(buffer),ENDCHAR,IGNCHARS,SECS,USEC);
-	dstate_setinfo("ups.model", "%.2s",buffer);
-	printf("Found %.2s family of Oneac UPS\n", buffer);
+	/* Setup some ON/OZ/OB only stuff ... i.e. not EG */
+	
+	if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) != 0)
+	{
+		dstate_addcmd("reset.input.minmax");
+		
+		/*nominal input voltage*/
 
-	if ((strncmp(buffer,FAMILY_ON,2) != 0 && 
-		 strncmp(buffer,FAMILY_ON_EXT,2) != 0) || 
-		strncmp(buffer,FAMILY_EG,2) == 0) 
-		printf("Unknown family of UPS. Assuming EG capabilities.\n");
+		VRange = buffer[26];			/* Keep for later use also */
+		
+		switch (VRange)					/* Will be '1' or '2' */
+		{
+			case V120AC:
+				dstate_setinfo("input.voltage.nominal", "120");
+				dstate_setinfo("output.voltage.nominal", "120");
+				break;
 
-	/*Get the actual model string for ON UPS reported as OZ family*/
-	if (strncmp (dstate_getinfo("ups.model"), FAMILY_ON_EXT, 2) == 0) {
+			case V230AC:
+				dstate_setinfo("input.voltage.nominal", "230");
+				dstate_setinfo("output.voltage.nominal", "230");
+				break;
+
+			default:
+				upslogx(LOG_INFO,"Oneac: "
+					"Invalid nom voltage parameter from UPS [%c]", VRange);
+		}
+	}
+		  
+	/* Setup some OZ/OB only stuff */
+	
+	if ((strncmp (UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) ||
+		(strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0))
+	{
+		dstate_addcmd("test.panel.start");
+		dstate_addcmd("test.battery.start.deep");
+		dstate_addcmd("beeper.enable");
+		dstate_addcmd("beeper.disable");
+		dstate_addcmd("beeper.mute");
+		
+		dstate_setaux("ups.delay.shutdown", GETX_SHUTDOWN_RESP_SIZE);
+
 		ser_flush_in(upsfd,"",0);
-		ser_send(upsfd,"%c%s",GET_ALL_EXT_2,COMMAND_END);
-		ser_get_line(upsfd, buffer, sizeof(buffer),ENDCHAR,IGNCHARS,SECS,USEC);
+		ser_send(upsfd,"%c%s",GETX_ALL_2,COMMAND_END);
+		if(OneacGetResponse (buffer, sizeof(buffer), GETX_ALL2_RESP_SIZE))
+		{
+			fatalx(EXIT_FAILURE, "Serial timeout(3) with ONEAC UPS on %s\n",
+																device_path);
+		}
 
+		/* Low and high output trip points */
+		EliminateLeadingZeroes (buffer+73, 3, buffer2, sizeof(buffer2));
+		dstate_setinfo("input.transfer.low", "%s", buffer2);
+		dstate_setflags("input.transfer.low", ST_FLAG_STRING | ST_FLAG_RW );
+		dstate_setaux("input.transfer.low", 3);
+
+		EliminateLeadingZeroes (buffer+76, 3, buffer2, sizeof(buffer2));
+		dstate_setinfo("input.transfer.high", "%s", buffer2);
+		dstate_setflags("input.transfer.high", ST_FLAG_STRING | ST_FLAG_RW);
+		dstate_setaux("input.transfer.high", 3);
+
+		/* Restart delay */
+		EliminateLeadingZeroes (buffer+84, 4, buffer2, sizeof(buffer2));
+		dstate_setinfo("ups.delay.start", "%s", buffer2);
+		dstate_setflags("ups.delay.start", ST_FLAG_STRING | ST_FLAG_RW);
+		dstate_setaux("ups.delay.start", 4);
+		
+		/* Low Batt at time */
+		strncpy(buffer2, buffer+82, 2);
+		buffer2[2]='\0';
+		timevalue = atoi(buffer2) * 60;		/* Change minutes to seconds */
+		dstate_setinfo("battery.runtime.low", "%d",timevalue);
+		dstate_setflags("battery.runtime.low", ST_FLAG_STRING | ST_FLAG_RW);
+		dstate_setaux("battery.runtime.low", 2);
+		
+		/*Get the actual model string for ON UPS reported as OZ/OB family*/
+
 		/*UPS Model (full string)*/
 		memset(buffer2, '\0', 32);
-		strncpy(buffer2,&buffer[5], 10);
-		for (i = 9; i >= 0 && buffer2[i] == ' '; --i) {
+		strncpy(buffer2, buffer+5, 10);
+		for (i = 9; i >= 0 && buffer2[i] == ' '; --i) 
+		{
 			buffer2[i] = '\0';
 		}
 
-		dstate_setinfo("ups.model", "%s", buffer2);
-		printf("Found %.10s UPS\n", buffer2);
-	}
+		dstate_setinfo("device.model", "%s", buffer2);
+		
+		/* Serial number */
+		dstate_setinfo("device.serial", "%.4s-%.4s", buffer+18, buffer+22);
+		printf("Found %.10s UPS with serial number %.4s-%.4s\n", 
+												buffer2, buffer+18, buffer+22);
+		
+		/* Manufacture Date */
+		dstate_setinfo("ups.mfr.date", "%.6s (yymmdd)", buffer+38);
 
-	/*The ON (OZ) series of UPS supports more stuff than does the EG.
- 	*Take care of the ON (OZ) only stuff here
-	*/
-	if(strncmp (dstate_getinfo("ups.model"), FAMILY_ON, 2) == 0 ||
-	   strncmp (dstate_getinfo("ups.model"), FAMILY_ON_EXT, 2) == 0) {
-		/*now set the ON specific "static" parameters*/
+		/* Battery Replace Date */
+		dstate_setinfo("battery.date", "%.6s (yymmdd)", buffer+44);
+		dstate_setflags("battery.date", ST_FLAG_STRING | ST_FLAG_RW);
+		dstate_setaux("battery.date", 6);
+		
+		/* Real power nominal */
+		EliminateLeadingZeroes (buffer+55, 5, buffer2, sizeof(buffer2));
+		dstate_setinfo("ups.realpower.nominal", "%s", buffer2);
 
-			/*nominal input voltage*/
+		/* Set up ups.start.auto to be writable */
+		dstate_setinfo("ups.start.auto", "yes");
+		dstate_setflags("ups.start.auto", ST_FLAG_STRING | ST_FLAG_RW);
+		dstate_setaux("ups.start.auto", 3);
 
-		ser_send(upsfd,"%c%s",GET_NOM_VOLTAGE,COMMAND_END);
-		ser_get_line(upsfd,buffer,sizeof(buffer),ENDCHAR,IGNCHARS,SECS,USEC);
+		/* Get output window min/max points from OB or OZ v1.9 or later */
+		if ((strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0) ||
+			(strcmp (dstate_getinfo("ups.firmware"), MIN_ALLOW_FW) >= 0 ))
+		{
+			upsdebugx (2,"Can get output window min/max! (%s)", 
+												dstate_getinfo("ups.firmware"));
 
-		switch (buffer[0]) {
-			case V120AC:
-				dstate_setinfo("output.voltage.nominal", 
-					"120");
-				break;
+			ser_send(upsfd,"%s%s",GETX_ALLOW_RANGE,COMMAND_END);
+			if(OneacGetResponse (buffer, sizeof(buffer), GETX_RANGE_RESP_SIZE))
+			{
+				fatalx(EXIT_FAILURE, 
+						"Serial timeout(4) with ONEAC UPS on %s\n",device_path);
+			}
 
-			case V230AC:
-				dstate_setinfo("output.voltage.nominal", 
-					"240");
-				break;
+			strncpy(buffer2, buffer, 3);
+			buffer2[3]='\0';
+			i = atoi(buffer2);		/* Minimum voltage */
+			
+			strncpy(buffer2, buffer+4, 3);
+			j = atoi(buffer2);		/* Maximum voltage */
 
-			default:
-				upslogx(LOG_INFO,"Oneac: "
-					"Invalid voltage parameter from UPS");
+			strncpy(buffer2, buffer+8, 2);
+			buffer2[2]='\0';
+			k = atoi(buffer2);		/* Spread between */
+			
+			dstate_setinfo("input.transfer.low.min", "%3d", i);
+			dstate_setinfo("input.transfer.low.max", "%3d", j-k);
+			dstate_setinfo("input.transfer.high.min", "%3d", i+k);
+			dstate_setinfo("input.transfer.high.max", "%3d", j);
+
 		}
+		else
+		{
+			/* Use default values from firmware */
+			upsdebugx (2,"Using trip defaults (%s)...", 
+												dstate_getinfo("ups.firmware"));
+
+			switch (VRange)				/* Held from initial use */
+			{
+				case V120AC:
+					dstate_setinfo("input.transfer.low.min", "90");
+					dstate_setinfo("input.transfer.low.max", "120");
+					dstate_setinfo("input.transfer.high.min", "110");
+					dstate_setinfo("input.transfer.high.max", "140");
+					break;
+
+				case V230AC:
+					dstate_setinfo("input.transfer.low.min", "172");
+					dstate_setinfo("input.transfer.low.max", "228");
+					dstate_setinfo("input.transfer.high.min", "212");
+					dstate_setinfo("input.transfer.high.max", "268");
+					break;
+
+				default:
+					;
+
+			}
+		}
 	}
 }
 
 void upsdrv_updateinfo(void)
 {
-	char buffer[256];
-	int ret_value;
+static int CommTry = COMM_TRIES;		/* Comm loss counter */
 
+char buffer[256];	/* Main response buffer */
+char buffer2[32];	/* Conversion buffer */
+char s;
+int RetValue;
+int timevalue;
 
+	/* Start with EG/ON information */
+	
 	ser_flush_in(upsfd,"",0);  /*just in case*/
-	ser_send (upsfd,"%c%s",GET_ALL,COMMAND_END);
-	ret_value = ser_get_line(upsfd,buffer,sizeof(buffer),ENDCHAR,
-			IGNCHARS,SECS,USEC);
-	
-	upsdebugx (2,"upsrecv_updateinfo: upsrecv returned: %s\n",buffer);
-	if (ret_value < 1)
+	ser_send (upsfd,"%c%s", GET_ALL, COMMAND_END);
+
+	if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) == 0)
 	{
-		ser_comm_fail("Oneac UPS Comm failure on port %s",device_path);
-		dstate_datastale();
+		RetValue = OneacGetResponse (buffer,sizeof(buffer),GETALL_EG_RESP_SIZE);
 	}
 	else
 	{
+		RetValue = OneacGetResponse (buffer, sizeof(buffer), GETALL_RESP_SIZE);
+	}
+
+	if ((RetValue != 0) && (CommTry == 0))
+	{
+		ser_comm_fail("Oneac UPS Comm failure continues on port %s",
+																device_path);
+	}	
+	else if (RetValue != 0)
+	{
+		if (--CommTry == 0)
+		{
+			ser_comm_fail("Oneac UPS Comm failure on port %s",device_path);
+			dstate_datastale();
+		}
+
+		upsdebugx(2,"Oneac: Update serial comm retry value: %d", CommTry);
+			
+		return;
+	}
+	else
+	{
+		CommTry = COMM_TRIES;			/* Reset serial retries */
+		
+		s = buffer[12];
+		
 		status_init();
+		alarm_init();
+		
 		/*take care of the UPS status information*/
-		switch (buffer[12]) {
-			case NORMAL :
+		if (s == '@')
+		{
+			status_set("OL");
+		}
+		else
+		{
+			if (s & 0x01)			/* On Battery */
+			{
+				status_set("OB");
+			}
+			else
+			{
 				status_set("OL");
-				break;
-			case ON_BAT_LOW_LINE :
-			case ON_BAT_HI_LINE  :
-				status_set("OB");
-				break;
-			case LO_BAT_LOW_LINE :
-			case LO_BAT_HI_LINE  :
-				status_set("OB LB");
-				break;
-			case TOO_HOT :
-				status_set("OVER OB LB");
-				break;
-			case FIX_ME :
+			}
+			
+			if (s & 0x02)			/* Low Battery */
+				status_set("LB");
+			
+			if (s & 0x04)			/* General fault */
+			{
 				dstate_setinfo("ups.test.result","UPS Internal Failure");
-				break;
-			case BAD_BAT :
+			}
+			else
+			{
+				dstate_setinfo("ups.test.result","Normal");
+			}
+			
+			if (s & 0x08)			/* Replace Battery */
 				status_set("RB");
-				break;
-			default :				/*cry for attention, fake a status*/
-									/*Would another status be better?*/
-				upslogx (LOG_ERR, "Oneac: Unknown UPS status");
-				status_set("OL");
+
+/*			if (s & 0x10)	*/		/* High Line */
+
+			if (s & 0x20)			/* Unit is hot */
+				alarm_set("OVERHEAT");
 		}
-
-		/*take care of the reason why the UPS last transfered to battery*/
+		
+		/*take care of the reason why the UPS last transferred to battery*/
 		switch (buffer[13]) {
 			case XFER_BLACKOUT :
 				dstate_setinfo("input.transfer.reason",	"Blackout");
@@ -261,61 +572,474 @@
 				break;
 			default :
 				upslogx(LOG_INFO,"Oneac: Unknown reason for UPS battery"
-				" transfer");
+										" transfer [%c]", buffer[13]);
 		}
-		/* now update info for only the ON family of UPS*/
+		
+		/* now update info for only the non-EG families of UPS*/
 
-		if (strncmp(dstate_getinfo("ups.model"), FAMILY_ON, 2) == 0) {
+		if (strncmp(UpsFamily, FAMILY_EG, FAMILY_SIZE) != 0)
+		{
 			dstate_setinfo("ups.load", "0%.2s",buffer+31);
 
+			/* Output ON or OFF? */
+			
+			if(buffer[27] == NO_VALUE_YET)
+				status_set("OFF");
+			
 			/*battery charge*/
 			if(buffer[10] == YES)
 				dstate_setinfo("battery.charge", "0%.2s",buffer+33);
-			else dstate_setinfo("battery.charge", "100");
+			else 
+				dstate_setinfo("battery.charge", "100");
 
-			dstate_setinfo("input.voltage", "%.3s",buffer+35);
-			dstate_setinfo("input.voltage.minimum", "%.3s",buffer+38);
-			dstate_setinfo("input.voltage.maximum", "%.3s",buffer+41);
-			dstate_setinfo("output.voltage", "%.3s",buffer+44);
-			if (buffer[47] == YES) status_set("BOOST");
+			EliminateLeadingZeroes (buffer+35, 3, buffer2, sizeof(buffer2));
+			dstate_setinfo("input.voltage", "%s",buffer2);
+			
+			EliminateLeadingZeroes (buffer+38, 3, buffer2, sizeof(buffer2));
+			dstate_setinfo("input.voltage.minimum", "%s",buffer2);
+			
+			EliminateLeadingZeroes (buffer+41, 3, buffer2, sizeof(buffer2));
+			dstate_setinfo("input.voltage.maximum", "%s",buffer2);
+			
+			EliminateLeadingZeroes (buffer+44, 3, buffer2, sizeof(buffer2));
+			dstate_setinfo("output.voltage", "%s",buffer2);
+			
+			if (buffer[15] == NO_VALUE_YET)
+			{
+				dstate_delinfo("ups.timer.shutdown");
+			}
+			else
+			{
+				/* If 'FSDflag' exists in ups.conf send FSD status */
+				if (testvar("FSDflag") != 0)
+									status_set("FSD");
+				
+				if(buffer[15] != HIGH_COUNT)
+				{
+					EliminateLeadingZeroes (buffer+15, 3, buffer2, 
+															sizeof(buffer2));
+					dstate_setinfo("ups.timer.shutdown", "%s", buffer2);
+				}
+				else
+				{
+					dstate_setinfo("ups.timer.shutdown", "999");
+				}
+			}
+			
+			if (buffer[47] == YES) 
+					status_set("BOOST");
 		}
+		
+		/* Now update info for only the OZ/OB families of UPS */
+		
+		if ((strncmp(UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) ||
+			(strncmp(UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0)) 
+		{
+			ser_flush_in(upsfd,"",0);  /*just in case*/
+			ser_send (upsfd,"%c%s",GETX_ALL_1,COMMAND_END);
+			RetValue = OneacGetResponse (buffer, sizeof(buffer), 
+														GETX_ALL1_RESP_SIZE);
+
+			if(RetValue)
+			{
+				if (--CommTry == 0)
+				{
+					ser_comm_fail("Oneac (OZ) UPS Comm failure on port %s",
+																device_path);
+					dstate_datastale();
+				}
+
+				upsdebugx(2,"Oneac: "
+					"Update (OZ) serial comm retry value: %d", CommTry);
+			}
+			else
+			{
+				CommTry = COMM_TRIES;		/* Reset count */
+				
+				EliminateLeadingZeroes (buffer+57, 5, buffer2, sizeof(buffer2));
+				dstate_setinfo("ups.realpower", "%s",buffer2);
+				
+				dstate_setinfo("input.frequency", "%.2s.%c",
+														buffer+42,buffer[44]);
+				dstate_setinfo("output.frequency", "%.2s.%c",
+														buffer+76, buffer[78]);
+				
+				EliminateLeadingZeroes (buffer+29, 3, buffer2, sizeof(buffer2));
+				dstate_setinfo("battery.voltage", "%s.%c",buffer2, buffer[32]);
+
+				dstate_setinfo("ups.temperature", "%.2s",buffer+13);
+				dstate_setinfo("ups.load", "%.3s",buffer+73);
+				
+				strncpy(buffer2, buffer+19, 4);
+				buffer2[4]='\0';
+				timevalue = atoi(buffer2) * 60;		/* Change mins to secs */
+				dstate_setinfo("battery.runtime", "%d",timevalue);
+				
+				/* Now some individual requests... */
+
+				/* Battery replace date */
+				ser_send (upsfd,"%c%s",GETX_BATT_REPLACED,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 
+														GETX_DATE_RESP_SIZE))
+					dstate_setinfo("battery.date", "%.6s (yymmdd)", buffer);
+
+				/* Low and high output trip points */
+				ser_send (upsfd,"%c%s",GETX_LOW_OUT_ALLOW,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 
+														GETX_ALLOW_RESP_SIZE))
+				{
+					EliminateLeadingZeroes (buffer, 3, buffer2,sizeof(buffer2));
+					dstate_setinfo("input.transfer.low", "%s", buffer2);
+				}
+						
+				ser_send (upsfd,"%c%s",GETX_HI_OUT_ALLOW,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 
+														GETX_ALLOW_RESP_SIZE))
+					dstate_setinfo("input.transfer.high", "%s", buffer);
+
+				/* Restart delay */
+				ser_send (upsfd,"%c%s",GETX_RESTART_DLY,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 
+														GETX_RSTRT_RESP_SIZE))
+				{
+					EliminateLeadingZeroes (buffer, 4, buffer2, 
+															sizeof(buffer2));
+					dstate_setinfo("ups.delay.start", "%s", buffer2);
+				}					
+
+				/* Buzzer state */
+				ser_send (upsfd,"%s%s",GETX_BUZZER_WHAT,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 1))
+				{
+					switch (buffer[0]) 
+					{
+						case BUZZER_ENABLED :
+							dstate_setinfo("ups.beeper.status",	"enabled");
+							break;
+						case BUZZER_DISABLED :
+							dstate_setinfo("ups.beeper.status",	"disabled");
+							break;
+						case BUZZER_MUTED :
+							dstate_setinfo("ups.beeper.status",	"muted");
+							break;
+							
+						default :
+							dstate_setinfo("ups.beeper.status",	"enabled");
+					}
+				}
+
+				/* Auto start setting */
+				ser_send (upsfd,"%s%s",GETX_AUTO_START,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 1))
+				{
+					if (buffer[0] == '0')
+						dstate_setinfo("ups.start.auto", "yes");
+					else
+						dstate_setinfo("ups.start.auto", "no");
+				}
+
+				/* Low Batt at time */
+				ser_send (upsfd,"%c%s",GETX_LOW_BATT_TIME,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 2))
+				{
+					strncpy(buffer2, buffer, 2);
+					buffer2[2]='\0';
+					timevalue = atoi(buffer2) * 60;		/* Mins to secs */
+					dstate_setinfo("battery.runtime.low", "%d",timevalue);
+				}
+				
+				/* Shutdown timer */
+				ser_send (upsfd,"%c%s",GETX_SHUTDOWN,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 
+													GETX_SHUTDOWN_RESP_SIZE))
+				{
+					/* ON would have handled NO_VALUE_YET and setting FSD 
+					 *  above so only deal with counter value here.
+					 */
+					if (buffer[0] != NO_VALUE_YET)
+					{
+						EliminateLeadingZeroes (buffer, 5, buffer2, 
+															sizeof(buffer2));
+						dstate_setinfo("ups.timer.shutdown", "%s", buffer2);
+					}
+				}
+				
+				/* Restart timer */
+				ser_send (upsfd,"%s%s",GETX_RESTART_COUNT,COMMAND_END);
+				if(!OneacGetResponse (buffer, sizeof(buffer), 
+														GETX_RSTRT_RESP_SIZE))
+				{
+					if (atoi(buffer) == 0)
+					{
+						dstate_delinfo("ups.timer.start");
+					}
+					else
+					{
+						EliminateLeadingZeroes (buffer, 4, buffer2, 
+															sizeof(buffer2));
+						dstate_setinfo("ups.timer.start", "%s", buffer2);
+					}
+				}
+			}
+		}
+		
+		alarm_commit();
 		status_commit();
-		dstate_dataok();
-		ser_comm_good();
+
+		/* If the comm retry counter is zero then datastale has been set.
+		 *  We don't want to set dataok or ser_comm_good if that is the case.
+		 */
+		 
+		if (CommTry != 0)
+		{
+			dstate_dataok();
+			ser_comm_good();
+		}
 	}
 }
+
 void upsdrv_shutdown(void)
 {
 	ser_send(upsfd,"%s",SHUTDOWN);
 }
 
-
 void upsdrv_help(void)
 {
 	printf("\n---------\nNOTE:\n");
 	printf("You must set the UPS interface card DIP switch to 9600BPS\n");
 }
 
+void upsdrv_cleanup(void)
+{
+	ser_close(upsfd, device_path);
+}
+
 void upsdrv_makevartable(void)
 {
 	addvar(VAR_VALUE,"testtime",
-		"Change battery test time from 2 minute default.");
+		"Change battery test time from the 2 minute default.");
+	
+	addvar(VAR_VALUE,"shuttime",
+		"Change shutdown delay time from 0 second default.");
+	
+	addvar(VAR_FLAG,"FSDflag",
+		"If this flag is present the FSD status will be sent\n"
+			"whenever a UPS shutdown with delay becomes active.");
 }
 
-void upsdrv_initups(void)
+int instcmd(const char *cmdname, const char *extra)
 {
-	upsfd = ser_open(device_path);
-	ser_set_speed(upsfd, device_path, B9600);
+int i;
 
-/*get the UPS in the right frame of mind*/
+	upsdebugx(2, "In instcmd with %s and extra %s.", cmdname, extra);
+
+	if (!strcasecmp(cmdname, "test.failure.start")) {
+		ser_send(upsfd,"%s%s",SIM_PWR_FAIL,COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "shutdown.return")) {
+
+		i = atoi(dstate_getinfo("ups.delay.shutdown"));
+		
+		if ((strncmp (UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) ||
+			(strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0))
+		{
+			upsdebugx(3, "Shutdown using %c%d...", DELAYED_SHUTDOWN_PREFIX, i);
+			ser_send(upsfd,"%c%d%s",DELAYED_SHUTDOWN_PREFIX, i, COMMAND_END);
+		}
+		else
+		{
+			upsdebugx(3, "Shutdown using %c%03d...",DELAYED_SHUTDOWN_PREFIX, i);
+			ser_send(upsfd,"%c%03d%s",DELAYED_SHUTDOWN_PREFIX, i, COMMAND_END);
+		}
+					
+		return STAT_INSTCMD_HANDLED;
+	}
 	
-	ser_send(upsfd,"%s", COMMAND_END);
-	sleep (1);
-	ser_send(upsfd,"%s", COMMAND_END);
-	sleep (1);
+	if(!strcasecmp(cmdname, "shutdown.reboot")) {
+		ser_send(upsfd, "%s", SHUTDOWN);
+		return STAT_INSTCMD_HANDLED;
+	}
+	
+	if (!strcasecmp(cmdname, "shutdown.stop")) {
+		ser_send(upsfd,"%c%s",DELAYED_SHUTDOWN_PREFIX,COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "test.battery.start.quick")) {
+		do_battery_test();
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "test.battery.start.deep")) {
+		ser_send(upsfd, "%s%s", TEST_BATT_DEEP, COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "test.battery.stop")) 
+	{
+		if ((strncmp (UpsFamily, FAMILY_EG, FAMILY_SIZE) == 0) ||
+			(strncmp (UpsFamily, FAMILY_ON, FAMILY_SIZE) == 0))
+		{
+			ser_send(upsfd,"%s00%s",BAT_TEST_PREFIX,COMMAND_END);
+		}
+		else
+		{
+			ser_send(upsfd,"%c%s",TEST_ABORT,COMMAND_END);
+		}			
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "reset.input.minmax")) {
+		ser_send(upsfd,"%c%s",RESET_MIN_MAX, COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "beeper.enable")) {
+		ser_send(upsfd,"%c%c%s",SETX_BUZZER_PREFIX, BUZZER_ENABLED,COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "beeper.disable")) {
+		ser_send(upsfd,"%c%c%s",SETX_BUZZER_PREFIX,BUZZER_DISABLED,COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "beeper.mute")) {
+		ser_send(upsfd,"%c%c%s",SETX_BUZZER_PREFIX, BUZZER_MUTED, COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	if (!strcasecmp(cmdname, "test.panel.start")) {
+		ser_send(upsfd,"%s%s",TEST_INDICATORS, COMMAND_END);
+		return STAT_INSTCMD_HANDLED;
+	}
+
+	upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
+	return STAT_INSTCMD_UNKNOWN;
 }
 
-void upsdrv_cleanup(void)
+
+int setcmd(const char* varname, const char* setvalue)
 {
-	ser_close(upsfd, device_path);
+	upsdebugx(2, "In setcmd for %s with %s...", varname, setvalue);
+
+	if (!strcasecmp(varname, "ups.delay.shutdown"))
+	{
+		if ((strncmp (UpsFamily, FAMILY_OZ, FAMILY_SIZE) == 0) ||
+			(strncmp (UpsFamily, FAMILY_OB, FAMILY_SIZE) == 0))
+		{
+			if (atoi(setvalue) > 65535)
+			{
+				upsdebugx(2, "Too big for OZ/OB (>65535)...(%s)", setvalue);
+				return STAT_SET_UNKNOWN;
+			}
+		}
+		else
+		{
+			if (atoi(setvalue) > 999)
+			{
+				upsdebugx(2, "Too big for EG/ON (>999)...(%s)", setvalue);
+				return STAT_SET_UNKNOWN;
+			}
+		}
+		
+		dstate_setinfo("ups.delay.shutdown", "%s", setvalue);
+		return STAT_SET_HANDLED;
+	}
+	
+	if (!strcasecmp(varname, "input.transfer.low"))
+	{
+		if (SetOutputAllow(setvalue, dstate_getinfo("input.transfer.high")))
+		{
+			return STAT_SET_UNKNOWN;
+		}
+		else
+		{
+			dstate_setinfo("input.transfer.low" , "%s", setvalue);
+			return STAT_SET_HANDLED;
+		}
+	}
+	
+	if (!strcasecmp(varname, "input.transfer.high"))
+	{
+		if (SetOutputAllow(dstate_getinfo("input.transfer.low"), setvalue))
+		{
+			return STAT_SET_UNKNOWN;
+		}
+		else
+		{
+			dstate_setinfo("input.transfer.high" , "%s", setvalue);
+			return STAT_SET_HANDLED;
+		}
+	}
+	
+	if (!strcasecmp(varname, "battery.date"))
+	{
+		if(strlen(setvalue) == GETX_DATE_RESP_SIZE)		/* yymmdd (6 chars) */
+		{
+			ser_send(upsfd, "%s%s%s", SETX_BATTERY_DATE, setvalue, COMMAND_END);
+			dstate_setinfo("battery.date", "%s (yymmdd)", setvalue);
+			return STAT_SET_HANDLED;
+		}
+		else
+		{
+			return STAT_SET_UNKNOWN;
+		}
+	}
+	
+	if (!strcasecmp(varname, "ups.delay.start"))
+	{
+		if (atoi(setvalue) <= 9999)
+		{
+			ser_send(upsfd,"%s%s%s",SETX_RESTART_DELAY, setvalue, COMMAND_END);
+	
+			dstate_setinfo("ups.delay.start", "%s", setvalue);
+			return STAT_SET_HANDLED;
+		}
+		else
+		{
+			return STAT_SET_UNKNOWN;
+		}
+	}
+	
+	if (!strcasecmp(varname, "battery.runtime.low"))
+	{
+		if (atoi(setvalue) <= 99)
+		{
+			ser_send(upsfd,"%s%s%s",SETX_LOWBATT_AT, setvalue, COMMAND_END);
+	
+			dstate_setinfo("battery.runtime.low", "%s", setvalue);
+			return STAT_SET_HANDLED;
+		}
+		else
+		{
+			return STAT_SET_UNKNOWN;
+		}
+	}
+
+	if (!strcasecmp(varname, "ups.start.auto"))
+	{
+		if (!strcasecmp(setvalue, "yes"))
+		{
+			ser_send(upsfd,"%c0%s",SETX_AUTO_START, COMMAND_END);
+			dstate_setinfo("ups.start.auto", "yes");
+			return STAT_SET_HANDLED;
+		}
+		else if (!strcasecmp(setvalue, "no"))
+		{
+			ser_send(upsfd,"%c1%s",SETX_AUTO_START, COMMAND_END);
+			dstate_setinfo("ups.start.auto", "no");
+			return STAT_SET_HANDLED;
+		}
+		
+		return STAT_SET_UNKNOWN;
+	}
+	
+	upslogx(LOG_NOTICE, "setcmd: unknown command [%s]", varname);
+
+	return STAT_SET_UNKNOWN;
 }
+
+
Index: drivers/oneac.h
===================================================================
--- drivers/oneac.h	(revision 3468)
+++ drivers/oneac.h	(working copy)
@@ -1,5 +1,6 @@
 /*
 Copyright (C) 2002 Eric Lawson <[email protected]>
+		(C) 2012 by Bill Elliot <[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
@@ -22,22 +23,27 @@
 #define COMMAND_END "\r\n"
 #define DEFAULT_BAT_TEST_TIME "02"
 
-/*Information requests*/
+/*Information requests -- EG level */
 
-#define GET_ALL '%'
-#define GET_ALL_EXT_2 '^'
-#define GET_ALL_EXT_1 '&'
-#define GET_MFR	'M'
-#define GET_FAMILY	'F'
-#define GET_VERSION	'N'
-#define GET_ON_INVERTER	'G'
-#define GET_BATLOW	'K'
-#define GET_STATUS	'X'
-#define GET_LAST_XFER	'W'
+#define GET_ALL 	'%'
+#define	GETALL_EG_RESP_SIZE	22
+#define	GETALL_RESP_SIZE	48
+
+#define GET_MFR				'M'
+#define GET_FAMILY			'F'
+#define GET_VERSION			'N'
+#define GET_ON_INVERTER		'G'
+#define GET_BATLOW			'K'
+#define GET_STATUS			'X'
+#define GET_LAST_XFER		'W'
 #define GET_INVERTER_RDY	'I'
-#define GET_TEST_TIME	'Q'
-#define GET_NOM_FREQ	'H'
-#define GET_NOM_VOLTAGE 'V'
+#define	GET_SHUTDOWN		'O'
+#define GET_TEST_TIME		'Q'
+#define GET_NOM_FREQ		'H'
+
+/*Information requests -- ON level (EG plus these) */
+
+#define GET_NOM_VOLTAGE 	'V'
 #define GET_DISPLAY_CODE	'D'
 #define	GET_CONDITION_CODE	'C'
 #define GET_PERCENT_LOAD	'P'
@@ -45,48 +51,124 @@
 #define	GET_INPUT_LINE_VOLT	'L'
 #define GET_MIN_INPUT_VOLT	'A'
 #define GET_MAX_INPUT_VOLT	'E'
-#define	GET_OUTPUT_VOLT	'S'
-#define GET_BOOSTING	'B'
+#define	GET_OUTPUT_VOLT		'S'
+#define GET_BOOSTING		'B'
 
-/*Control functions*/
-#define	SIM_PWR_FAIL	"\x02\x15"		/*^B^U   15 second battery test*/
-#define SHUTDOWN	"\x0f\x06"			/*^O^F   (a letter O)*/
+#define	GET_SHUTDOWN_RESP_SIZE	3
+
+/*Information requests -- OZ/OB level (ON plus these) */
+
+#define GETX_ALL_1 	'&'
+#define	GETX_ALL1_RESP_SIZE	79
+
+#define	GETX_OUTSOURCE		'a'
+#define GETX_FRONTDISP		'b'
+#define GETX_INT_TEMP		'g'		/* Degrees C */
+#define GETX_BATT_STAT		'h'		/* Unknown(1), Normal, Low, Depleted */
+#define GETX_BATT_CHG_PERC	'i'		/* 0 - 100 */
+#define GETX_EST_MIN_REM	'j'
+#define GETX_ONBATT_TIME	'k'		/* In seconds */
+#define GETX_BATT_VOLTS		'l'		/* Read as xxx.x */
+#define GETX_INP_FREQ		'p'
+#define GETX_MIN_IN_VOLTS	'q'
+#define GETX_MAX_IN_VOLTS	'r'
+#define GETX_IN_VOLTS		's'
+#define GETX_IN_WATTS		'u'
+#define GETX_OUT_VOLTS		'v'
+#define GETX_OUT_WATTS		'x'
+#define GETX_OUT_LOAD_PERC	'y'
+#define GETX_OUT_FREQ		'z'
+
+#define GETX_ALL_2	'^'
+#define	GETX_ALL2_RESP_SIZE	92
+
+#define GETX_MODEL			'J'
+#define GETX_FW_REV			'U'		/* Read as xx.x */
+#define GETX_SERIAL_NUM		'Y'
+
+#define GETX_MAN_DATE		'$'		/* yymmdd */
+#define GETX_BATT_REPLACED	'+'		/* yymmdd */
+#define	GETX_DATE_RESP_SIZE	6
+
+#define GETX_UNIT_KVA		''''	/* Read as xxx.xx */
+#define GETX_UNIT_WATTS		"''"	/* 2-character string request */
+#define GETX_LOW_OUT_ALLOW	'['		/* Tap up or inverter at this point */
+#define GETX_HI_OUT_ALLOW	']'		/* Tap down or inverter at this point */
+#define GETX_NOTIFY_DELAY	','		/* Secs of delay for power fail alert */
+#define	GETX_ALLOW_RESP_SIZE	3
+
+#define GETX_LOW_BATT_TIME	'"'		/* Low batt alarm at xx minutes */
+
+#define	GETX_RESTART_DLY	'_'		/* Restart delay */
+#define	GETX_RESTART_COUNT	"_?"	/* Returns actual counter value */
+#define	GETX_RSTRT_RESP_SIZE	4
+
+/*Other requests */
+#define	GETX_SHUTDOWN		'}'			/* Shutdown counter (..... for none) */
+#define	GETX_SHUTDOWN_RESP_SIZE	5
+
+#define GETX_BATT_TEST_DAYS	"\x02\x1A"	/* Days between battery tests */
+#define	GETX_BUZZER_WHAT	"\x07?"		/* What is buzzer state */
+#define	GETX_AUTO_START		"<?"		/* Restart type */
+
+#define	GETX_ALLOW_RANGE	"[=?"		/* Responds with min,max,spread */
+#define	GETX_RANGE_RESP_SIZE	10
+
+/*Control functions (All levels) */
+#define	SIM_PWR_FAIL	"\x02\x15"	/*^B^U   15 second battery test*/
+#define SHUTDOWN		"\x0f\x06"	/*^O^F   (a letter O)*/
 #define RESET_MIN_MAX	'R'
-#define BAT_TEST_PREFIX	"\x02"		/*needs 2 more chars. minutes*/
-#define DELAYED_SHUTDOWN_PREFIX	'Z'	/*needs 3 more chars.  seconds */
+#define BAT_TEST_PREFIX	"\x02"		/*^B needs 2 more chars. minutes*/
+#define DELAYED_SHUTDOWN_PREFIX	'Z'	/* EG/ON needs 3 more chars.  seconds */
+									/* ON96 needs 1 to 5 chars. of seconds */
 
+/*Control functions (ON96) */
+#define TEST_INDICATORS	"\x09\x14"	/*^I^T flashed LEDs and beeper */
+#define	TEST_BATT_DEEP	"\x02\x04"	/*^B^D runs until low batt */
+#define	TEST_BATT_DEAD	"\x02\x12"	/*^B^R run until battery dead */
+#define	TEST_ABORT			'\x01'	/* Abort any running test */
+#define	REBOOT_LOAD			"\x12@"	/*^R@xxx needs 3 chars of secs */
+#define	SETX_BUZZER_PREFIX	'\x07'	/*^G needs one more character */
+#define	SETX_OUT_ALLOW		"[="	/* [=lll,hhh */
+#define	SETX_BUZZER_OFF		"\x070"	/*^G0 disables buzzer */
+#define	SETX_BUZZER_ON		"\x071"	/*^G1 enables buzzer */
+#define	SETX_BUZZER_MUTE	"\x072"		/*^G2 mutes current conditions */
+#define SETX_BATT_TEST_DAYS	"\x02\x1A="	/* Needs 0 - 129 days, 0 is disable */
+#define	SETX_LOWBATT_AT		"\"="		/* Low batt at (max 99) */
+#define	SETX_RESTART_DELAY	"_="		/* _=xxxx, up to 9999 seconds */
+#define	SETX_AUTO_START		'<'		/* <0 / <1 for auto / manual */
+#define	SETX_BATTERY_DATE	"+="	/* Set battery replace date */
+
 #define DONT_UNDERSTAND '*'
-#define CANT_COMPLY	'#'
-#define NO_VALUE_YET '.'
+#define CANT_COMPLY		'#'
+#define NO_VALUE_YET 	'.'
+#define HIGH_COUNT		'+'		/* Shutdown counter > 999 on OZ */
 
+#define MIN_ALLOW_FW	"1.9"	/* At or above provides output allow range */
 
 /*responses*/
-#define MFGR "ONEAC"
-#define FAMILY_ON	"ON"
-#define FAMILY_ON_EXT	"OZ"
-#define FAMILY_EG	"EG"
-#define YES	'Y'
-#define NO 'N'
-#define NORMAL '@'
-#define ON_BAT_LOW_LINE 'A'
-#define ON_BAT_HI_LINE 'Q'
-#define LO_BAT_LOW_LINE 'C'
-#define LO_BAT_HI_LINE 'S'
-#define TOO_HOT '`'
-#define FIX_ME 'D'
-#define BAD_BAT 'H'
-#define V230AC '2'
-#define V120AC '1'
-#define XFER_BLACKOUT 'B'
-#define XFER_LOW_VOLT 'L'
-#define XFER_HI_VOLT 'H' 
+#define FAMILY_EG		"EG"	/* 3 tri-color LEDs and big ON/OFF on front */
+#define FAMILY_ON		"ON"	/* Serial port avail only on interface card */
+#define FAMILY_OZ		"OZ"	/* DB-25 std., plus interface slot */
+#define	FAMILY_OB		"OB"	/* Lg. cab with removable modules */
+#define	FAMILY_SIZE		2
+#define YES				'Y'
+#define NO				'N'
+#define V230AC			'2'
+#define V120AC			'1'
+#define XFER_BLACKOUT	'B'
+#define XFER_LOW_VOLT	'L'
+#define XFER_HI_VOLT	'H' 
+#define	BUZZER_ENABLED	'1'
+#define BUZZER_DISABLED	'0'
+#define	BUZZER_MUTED	'2'
 
 /*front panel alarm codes*/
-#define CODE_BREAKER_OPEN "c1"		/*input circuit breaker open*/
-#define CODE_BAT_FUSE_OPEN "c2"		/*battery not connected. Open fuse?*/
-#define CODE_TOO_HOT "c3"			/*UPS too hot*/
-#define CODE_CHARGING "c4"			/*recharging battery pack*/
-#define CODE_LOW_BAT_CAP "c5"		/*batteries getting too old*/
-#define CODE_OVERLOAD "c8"			/*"slight" overload*/
-#define CODE_GROSS_OVLE "c9"		/*gross overload 1 minute to power off*/
+#define CODE_BREAKER_OPEN	"c1"	/*input circuit breaker open*/
+#define CODE_BAT_FUSE_OPEN	"c2"	/*battery not connected. Open fuse?*/
+#define CODE_TOO_HOT		"c3"	/*UPS too hot*/
+#define CODE_CHARGING		"c4"	/*recharging battery pack*/
+#define CODE_LOW_BAT_CAP	"c5"	/*batteries getting too old*/
+#define CODE_OVERLOAD		"c8"	/*"slight" overload*/
+#define CODE_GROSS_OVLE		"c9"	/*gross overload 1 minute to power off*/
 #define CODE_CHRGR_FUSE_OPEN "u1"	/*battery charger fuse probably open*/



_______________________________________________
Nut-upsdev mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/nut-upsdev

Reply via email to