Imported Upstream version 2.6.1
This commit is contained in:
parent
459aaf9392
commit
a367d9bc54
178 changed files with 4651 additions and 3279 deletions
|
@ -68,7 +68,6 @@ DIST_COMMON = $(dist_noinst_HEADERS) $(srcdir)/Makefile.am \
|
|||
$(srcdir)/Makefile.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
|
||||
$(top_srcdir)/m4/ax_create_stdint_h.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
|
|
|
@ -146,16 +146,38 @@ static usage_lkp_t apc_usage_lkp[] = {
|
|||
{ "APCProbe1", 0xff860007 },
|
||||
{ "APCProbe2", 0xff860008 },
|
||||
{ "APCBattReplaceDate", 0xff860016 },
|
||||
/* usage seen in dumps but unknown:
|
||||
* - ff860018
|
||||
* Path: UPS.Battery.ff860018, Type: Feature, ReportID: 0x48, Offset: 0, Size: 32, Value: 0
|
||||
*/
|
||||
{ "APCBattCapBeforeStartup", 0xff860019 }, /* FIXME: exploit */
|
||||
/* usage seen in dumps but unknown:
|
||||
* - ff86001a
|
||||
* Path: UPS.Battery.ff86001a, Type: Input, ReportID: 0x1b, Offset: 0, Size: 8, Value: 3
|
||||
* Path: UPS.Battery.ff86001a, Type: Feature, ReportID: 0x1b, Offset: 0, Size: 8, Value: 3
|
||||
* - ff86001b
|
||||
* Path: UPS.Battery.ff86001b, Type: Input, ReportID: 0x1c, Offset: 0, Size: 8, Value: 0
|
||||
* Path: UPS.Battery.ff86001b, Type: Feature, ReportID: 0x1c, Offset: 0, Size: 8, Value: 0
|
||||
* - ff860023
|
||||
* Path: UPS.ff860001.ff860023, Type: Feature, ReportID: 0x60, Offset: 0, Size: 16, Value: 0
|
||||
* - ff860024
|
||||
* Path: UPS.Battery.ff860024, Type: Feature, ReportID: 0x47, Offset: 0, Size: 8, Value: 245
|
||||
* Path: UPS.PowerConverter.ff860024, Type: Feature, ReportID: 0x51, Offset: 0, Size: 8, Value: 145
|
||||
* - ff860025
|
||||
* Path: UPS.ff860001.ff860025, Type: Feature, ReportID: 0x62, Offset: 0, Size: 32, Value: 0
|
||||
* - ff860026
|
||||
* Path: UPS.ff860001.ff860026, Type: Feature, ReportID: 0x61, Offset: 0, Size: 8, Value: 10
|
||||
* - ff860027
|
||||
* Path: UPS.ff860027, Type: Feature, ReportID: 0x3e, Offset: 0, Size: 32, Value: 0
|
||||
* - ff860028
|
||||
* Path: UPS.ff860028, Type: Feature, ReportID: 0x3f, Offset: 0, Size: 32, Value: 0
|
||||
* - ff860030
|
||||
* Path: UPS.Output.ff860030, Type: Feature, ReportID: 0x42, Offset: 0, Size: 16, Value: 5.8
|
||||
*/
|
||||
{ "APC_UPS_FirmwareRevision", 0xff860042 },
|
||||
{ "APCLineFailCause", 0xff860052 },
|
||||
{ "APCStatusFlag", 0xff860060 },
|
||||
{ "APCSensitivity", 0xff860061 },
|
||||
/* usage seen in dumps but unknown:
|
||||
* - ff860027, ff860028
|
||||
* Path: UPS.ff860027, Type: Feature, ReportID: 0x3e, Offset: 0,
|
||||
* Size: 32, Value:0.000000
|
||||
*/
|
||||
{ "APCPanelTest", 0xff860072 }, /* FIXME: exploit */
|
||||
{ "APCShutdownAfterDelay", 0xff860076 }, /* FIXME: exploit */
|
||||
{ "APC_USB_FirmwareRevision", 0xff860079 }, /* FIXME: exploit */
|
||||
|
@ -164,14 +186,24 @@ static usage_lkp_t apc_usage_lkp[] = {
|
|||
{ "APCDelayBeforeStartup", 0xff86007e }, /* FIXME: exploit */
|
||||
/* usage seen in dumps but unknown:
|
||||
* - ff860080
|
||||
* Path: UPS.PresentStatus.ff860080, Type: Input, ReportID: 0x33,
|
||||
* Offset: 12, Size: 1, Value: 0.000000
|
||||
* - ff86001a
|
||||
* Path: UPS.Battery.ff86001a, Type: Input, ReportID: 0x1b,
|
||||
* Offset: 0, Size: 8, Value: 3.000000
|
||||
* - ff86001b
|
||||
* Path: UPS.Battery.ff86001b, Type: Input, ReportID: 0x1c,
|
||||
* Offset: 0, Size: 8, Value: 0.000000
|
||||
* Path: UPS.PresentStatus.ff860080, Type: Input, ReportID: 0x33, Offset: 12, Size: 1, Value: 0
|
||||
* Path: UPS.PresentStatus.ff860080, Type: Feature, ReportID: 0x33, Offset: 12, Size: 1, Value: 0
|
||||
* Path: UPS.PowerSummary.PresentStatus.ff860080, Type: Input, ReportID: 0x07, Offset: 12, Size: 1, Value: 0
|
||||
* Path: UPS.PowerSummary.PresentStatus.ff860080, Type: Feature, ReportID: 0x07, Offset: 12, Size: 1, Value: 0
|
||||
* - ff860090, ff860091
|
||||
* Path: UPS.ff860090.ff860091, Type: Feature, ReportID: 0x8c, Offset: 0, Size: 8, Value: 1.000000
|
||||
* - ff860092
|
||||
* Path: UPS.ff860090.ff860092, Type: Feature, ReportID: 0x8d, Offset: 0, Size: 8, Value: 25.000000
|
||||
* - ff860093
|
||||
* Path: UPS.ff860090.ff860093, Type: Feature, ReportID: 0x8e, Offset: 0, Size: 8, Value: 83.000000
|
||||
* - ff860094
|
||||
* Path: UPS.ff860090.ff860094, Type: Feature, ReportID: 0x8f, Offset: 0, Size: 8, Value: 0.000000
|
||||
* - ff860095
|
||||
* Path: UPS.ff860090.ff860095, Type: Feature, ReportID: 0x90, Offset: 0, Size: 8, Value: 1.000000
|
||||
* - ff860096
|
||||
* Path: UPS.ff860090.ff860096, Type: Feature, ReportID: 0x91, Offset: 0, Size: 16, Value: 4.000000
|
||||
* - ff860097
|
||||
* Path: UPS.ff860090.ff860097, Type: Feature, ReportID: 0x92, Offset: 0, Size: 16, Value: 4.000000
|
||||
*/
|
||||
|
||||
/* Note (Arnaud): BUP stands for BackUPS Pro
|
||||
|
@ -269,12 +301,12 @@ static hid_info_t apc_hid2nut[] = {
|
|||
{ "ups.timer.start", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL},
|
||||
{ "ups.timer.shutdown", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL},
|
||||
{ "ups.timer.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL},
|
||||
|
||||
{ "ups.test.result", 0, 0, "UPS.Battery.Test", NULL, "%s", 0, test_read_info },
|
||||
{ "ups.beeper.status", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", 0, beeper_info },
|
||||
{ "ups.mfr.date", 0, 0, "UPS.ManufacturerDate", NULL, "%s", 0, date_conversion },
|
||||
{ "ups.mfr.date", 0, 0, "UPS.PowerSummary.ManufacturerDate", NULL, "%s", 0, date_conversion }, /* Back-UPS 500 */
|
||||
{ "ups.realpower.nominal", 0, 0, "UPS.PowerConverter.ConfigActivePower", NULL, "%.0f", 0, NULL },
|
||||
{ "ups.realpower.nominal", 0, 0, "UPS.PowerConverter.ConfigActivePower", NULL, "%.0f", 0, NULL },
|
||||
{ "ups.realpower.nominal", 0, 0, "UPS.Output.ConfigActivePower", NULL, "%.0f", 0, NULL },
|
||||
|
||||
/* the below one need to be discussed as we might need to complete
|
||||
* the ups.test sub collection
|
||||
|
@ -306,13 +338,18 @@ static hid_info_t apc_hid2nut[] = {
|
|||
/* Input page */
|
||||
{ "input.voltage", 0, 0, "UPS.Input.Voltage", NULL, "%.1f", 0, NULL },
|
||||
{ "input.voltage.nominal", 0, 0, "UPS.Input.ConfigVoltage", NULL, "%.0f", 0, NULL },
|
||||
{ "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Output.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
/* used by APC BackUPS RS */
|
||||
{ "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.LowVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.HighVoltageTransfer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "input.sensitivity", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.Input.APCSensitivity", NULL, "%s", HU_FLAG_SEMI_STATIC, apc_sensitivity_info },
|
||||
|
||||
|
||||
/* Output page */
|
||||
{ "output.voltage", 0, 0, "UPS.Output.Voltage", NULL, "%.1f", 0, NULL },
|
||||
{ "output.voltage.nominal", 0, 0, "UPS.Output.ConfigVoltage", NULL, "%.1f", 0, NULL },
|
||||
{ "output.current", 0, 0, "UPS.Output.Current", NULL, "%.2f", 0, NULL },
|
||||
{ "output.frequency", 0, 0, "UPS.Output.Frequency", NULL, "%.1f", 0, NULL },
|
||||
|
||||
/* Environmental page */
|
||||
{ "ambient.temperature", 0, 0, "UPS.APCEnvironment.APCProbe1.Temperature", NULL, "%s", 0, kelvin_celsius_conversion },
|
||||
|
@ -352,7 +389,9 @@ static hid_info_t apc_hid2nut[] = {
|
|||
{ "load.on.delay", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeStartup", NULL, DEFAULT_ONDELAY, HU_TYPE_CMD, NULL },
|
||||
{ "shutdown.stop", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeShutdown", NULL, "-1", HU_TYPE_CMD, NULL },
|
||||
{ "shutdown.reboot", 0, 0, "UPS.APCGeneralCollection.APCDelayBeforeReboot", NULL, "10", HU_TYPE_CMD, NULL },
|
||||
|
||||
/* used by APC BackUPS CS */
|
||||
{ "shutdown.return", 0, 0, "UPS.Output.APCDelayBeforeReboot", NULL, "1", HU_TYPE_CMD, NULL },
|
||||
|
||||
{ "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL },
|
||||
{ "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "3", HU_TYPE_CMD, NULL },
|
||||
{ "beeper.enable", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", HU_TYPE_CMD, NULL },
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "apcsmart.h"
|
||||
|
||||
#define DRIVER_NAME "APC Smart protocol driver"
|
||||
#define DRIVER_VERSION "2.03"
|
||||
#define DRIVER_VERSION "2.1"
|
||||
|
||||
static upsdrv_info_t table_info = {
|
||||
"APC command table",
|
||||
|
@ -38,8 +38,9 @@ static upsdrv_info_t table_info = {
|
|||
upsdrv_info_t upsdrv_info = {
|
||||
DRIVER_NAME,
|
||||
DRIVER_VERSION,
|
||||
"Russell Kroll <rkroll@exploits.org>\n" \
|
||||
"Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>",
|
||||
"Russell Kroll <rkroll@exploits.org>\n"
|
||||
"Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>\n"
|
||||
"Michal Soltys <soltys@ziu.info>",
|
||||
DRV_STABLE,
|
||||
{ &table_info, NULL }
|
||||
};
|
||||
|
@ -73,7 +74,7 @@ static apc_vartab_t *vartab_lookup_name(const char *var)
|
|||
/* FUTURE: change to use function pointers */
|
||||
|
||||
/* convert APC formatting to NUT formatting */
|
||||
static const char *convert_data(apc_vartab_t *cmd_entry, char *upsval)
|
||||
static const char *convert_data(apc_vartab_t *cmd_entry, const char *upsval)
|
||||
{
|
||||
static char tmp[128];
|
||||
int tval;
|
||||
|
@ -178,6 +179,16 @@ static void alert_handler(char ch)
|
|||
ups_status |= APC_STAT_RB;
|
||||
break;
|
||||
|
||||
case '?': /* set OVER */
|
||||
upsdebugx(4, "alert_handler: OVER");
|
||||
ups_status |= APC_STAT_OVER;
|
||||
break;
|
||||
|
||||
case '=': /* clear OVER */
|
||||
upsdebugx(4, "alert_handler: not OVER");
|
||||
ups_status &= ~APC_STAT_OVER;
|
||||
break;
|
||||
|
||||
default:
|
||||
upsdebugx(4, "alert_handler got 0x%02x (unhandled)", ch);
|
||||
break;
|
||||
|
@ -252,8 +263,10 @@ static int query_ups(const char *var, int first)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* already known to not be supported? */
|
||||
if (vt->flags & APC_IGNORE)
|
||||
/*
|
||||
* not first run and already known to not be supported ?
|
||||
*/
|
||||
if (!first && !(vt->flags & APC_PRESENT))
|
||||
return 0;
|
||||
|
||||
/* empty the input buffer (while allowing the alert handler to run) */
|
||||
|
@ -278,11 +291,10 @@ static int query_ups(const char *var, int first)
|
|||
|
||||
ser_comm_good();
|
||||
|
||||
if ((ret < 1) || (!strcmp(temp, "NA"))) { /* not supported */
|
||||
vt->flags |= APC_IGNORE;
|
||||
if ((ret < 1) || (!strcmp(temp, "NA"))) /* not supported */
|
||||
return 0;
|
||||
}
|
||||
|
||||
vt->flags |= APC_PRESENT;
|
||||
ptr = convert_data(vt, temp);
|
||||
dstate_setinfo(vt->name, "%s", ptr);
|
||||
|
||||
|
@ -293,7 +305,7 @@ static void do_capabilities(void)
|
|||
{
|
||||
const char *ptr, *entptr;
|
||||
char upsloc, temp[512], cmd, loc, etmp[16], *endtemp;
|
||||
int nument, entlen, i, matrix, ret;
|
||||
int nument, entlen, i, matrix, ret, valid;
|
||||
apc_vartab_t *vt;
|
||||
|
||||
upsdebugx(1, "APC - About to get capabilities string");
|
||||
|
@ -324,7 +336,7 @@ static void do_capabilities(void)
|
|||
/* This should never happen since we only call
|
||||
this if the REQ_CAPABILITIES command is supported
|
||||
*/
|
||||
upslogx(LOG_ERR, "ERROR: APC cannot do capabilites but said it could!");
|
||||
upslogx(LOG_ERR, "ERROR: APC cannot do capabilities but said it could!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -333,8 +345,8 @@ static void do_capabilities(void)
|
|||
endtemp = &temp[0] + strlen(temp);
|
||||
|
||||
if (temp[0] != '#') {
|
||||
printf("Unrecognized capability start char %c\n", temp[0]);
|
||||
printf("Please report this error [%s]\n", temp);
|
||||
upsdebugx(1, "Unrecognized capability start char %c", temp[0]);
|
||||
upsdebugx(1, "Please report this error [%s]", temp);
|
||||
upslogx(LOG_ERR, "ERROR: unknown capability start char %c!",
|
||||
temp[0]);
|
||||
|
||||
|
@ -377,9 +389,10 @@ static void do_capabilities(void)
|
|||
entptr = &ptr[4];
|
||||
|
||||
vt = vartab_lookup_char(cmd);
|
||||
valid = vt && ((loc == upsloc) || (loc == '4'));
|
||||
|
||||
/* mark this as writable */
|
||||
if (vt && ((loc == upsloc) || (loc == '4'))) {
|
||||
if (valid) {
|
||||
upsdebugx(1, "Supported capability: %02x (%c) - %s",
|
||||
cmd, loc, vt->name);
|
||||
|
||||
|
@ -390,11 +403,10 @@ static void do_capabilities(void)
|
|||
}
|
||||
|
||||
for (i = 0; i < nument; i++) {
|
||||
snprintf(etmp, entlen + 1, "%s", entptr);
|
||||
|
||||
if (vt && ((loc == upsloc) || (loc == '4')))
|
||||
dstate_addenum(vt->name, "%s",
|
||||
convert_data(vt, etmp));
|
||||
if (valid) {
|
||||
snprintf(etmp, entlen + 1, "%s", entptr);
|
||||
dstate_addenum(vt->name, "%s", convert_data(vt, etmp));
|
||||
}
|
||||
|
||||
entptr += entlen;
|
||||
}
|
||||
|
@ -430,7 +442,6 @@ static int update_status(void)
|
|||
ups_status = strtol(buf, 0, 16) & 0xff;
|
||||
ups_status_set();
|
||||
|
||||
status_commit();
|
||||
dstate_dataok();
|
||||
|
||||
return 1;
|
||||
|
@ -466,10 +477,6 @@ static void protocol_verify(unsigned char cmd)
|
|||
{
|
||||
int i, found;
|
||||
|
||||
/* we might not care about this one */
|
||||
if (strchr(CMD_IGN_CHARS, cmd))
|
||||
return;
|
||||
|
||||
/* see if it's a variable */
|
||||
for (i = 0; apc_vartab[i].name != NULL; i++) {
|
||||
|
||||
|
@ -531,27 +538,28 @@ static int firmware_table_lookup(void)
|
|||
unsigned int i, j;
|
||||
char buf[SMALLBUF];
|
||||
|
||||
upsdebugx(1, "Attempting firmware lookup");
|
||||
upsdebugx(1, "Attempting firmware lookup using command 'V'");
|
||||
|
||||
ret = ser_send_char(upsfd, 'b');
|
||||
ret = ser_send_char(upsfd, 'V');
|
||||
|
||||
if (ret != 1) {
|
||||
upslog_with_errno(LOG_ERR, "getbaseinfo: ser_send_char failed");
|
||||
upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_send_char failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ser_get_line(upsfd, buf, sizeof(buf), ENDCHAR, IGNCHARS,
|
||||
SER_WAIT_SEC, SER_WAIT_USEC);
|
||||
|
||||
/* see if this is an older version like an APC600 which doesn't
|
||||
* response to 'a' or 'b' queries
|
||||
/*
|
||||
* Some UPSes support both 'V' and 'b'. As 'b' doesn't always return
|
||||
* firmware version, we attempt that only if 'V' doesn't work.
|
||||
*/
|
||||
if ((ret < 1) || (!strcmp(buf, "NA"))) {
|
||||
upsdebugx(1, "Attempting to contact older Smart-UPS version");
|
||||
ret = ser_send_char(upsfd, 'V');
|
||||
upsdebugx(1, "Attempting firmware lookup using command 'b'");
|
||||
ret = ser_send_char(upsfd, 'b');
|
||||
|
||||
if (ret != 1) {
|
||||
upslog_with_errno(LOG_ERR, "getbaseinfo: ser_send_char failed");
|
||||
upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_send_char failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -562,10 +570,10 @@ static int firmware_table_lookup(void)
|
|||
upslog_with_errno(LOG_ERR, "firmware_table_lookup: ser_get_line failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
upsdebugx(2, "Firmware: [%s]", buf);
|
||||
}
|
||||
|
||||
upsdebugx(2, "Firmware: [%s]", buf);
|
||||
|
||||
/* this will be reworked if we get a lot of these things */
|
||||
if (!strcmp(buf, "451.2.I")) {
|
||||
quirk_capability_overflow = 1;
|
||||
|
@ -602,6 +610,10 @@ static void getbaseinfo(void)
|
|||
int ret = 0;
|
||||
char *alrts, *cmds, temp[512];
|
||||
|
||||
/*
|
||||
* try firmware lookup first; we could start with 'a', but older models
|
||||
* sometimes return other things than a command set
|
||||
*/
|
||||
if (firmware_table_lookup() == 1)
|
||||
return;
|
||||
|
||||
|
@ -622,7 +634,6 @@ static void getbaseinfo(void)
|
|||
SER_WAIT_SEC, SER_WAIT_USEC);
|
||||
|
||||
if ((ret < 1) || (!strcmp(temp, "NA"))) {
|
||||
|
||||
/* We have an old dumb UPS - go to specific code for old stuff */
|
||||
oldapcsetup();
|
||||
return;
|
||||
|
@ -774,101 +785,276 @@ static int smartmode(void)
|
|||
return 0; /* failure */
|
||||
}
|
||||
|
||||
/*
|
||||
* all shutdown commands should respond with 'OK' or '*'
|
||||
*/
|
||||
static int sdok(void)
|
||||
{
|
||||
char temp[16];
|
||||
|
||||
ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR, IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
|
||||
upsdebugx(4, "sdok: got \"%s\"", temp);
|
||||
|
||||
if (!strcmp(temp, "*") || !strcmp(temp, "OK")) {
|
||||
upsdebugx(4, "Last issued shutdown command succeeded");
|
||||
return 1;
|
||||
}
|
||||
|
||||
upsdebugx(1, "Last issued shutdown command failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* soft hibernate: S - working only when OB, otherwise ignored */
|
||||
static int sdcmd_S(int dummy)
|
||||
{
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
|
||||
upsdebugx(1, "Issuing soft hibernate");
|
||||
ser_send_char(upsfd, APC_CMD_SOFTDOWN);
|
||||
|
||||
return sdok();
|
||||
}
|
||||
|
||||
/* soft hibernate, hack version for CS 350 */
|
||||
static int sdcmd_CS(int tval)
|
||||
{
|
||||
upsdebugx(1, "Using CS 350 'force OB' shutdown method");
|
||||
if (tval & APC_STAT_OL) {
|
||||
upsdebugx(1, "On-line - forcing OB temporarily");
|
||||
ser_send_char(upsfd, 'U');
|
||||
usleep(UPSDELAY);
|
||||
}
|
||||
return sdcmd_S(tval);
|
||||
}
|
||||
|
||||
/*
|
||||
* hard hibernate: @nnn / @nn
|
||||
* note: works differently for older and new models, see help function for
|
||||
* detailed info
|
||||
*/
|
||||
static int sdcmd_ATn(int cnt)
|
||||
{
|
||||
int n = 0, mmax, ret;
|
||||
const char *strval;
|
||||
char timer[4];
|
||||
|
||||
mmax = cnt == 2 ? 99 : 999;
|
||||
|
||||
if ((strval = getval("wugrace"))) {
|
||||
errno = 0;
|
||||
n = strtol(strval, NULL, 10);
|
||||
if (errno || n < 0 || n > mmax)
|
||||
n = 0;
|
||||
}
|
||||
|
||||
snprintf(timer, sizeof(timer), "%.*d", cnt, n);
|
||||
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
upsdebugx(1, "Issuing hard hibernate with %d minutes additional wakeup delay", n*6);
|
||||
|
||||
ser_send_char(upsfd, APC_CMD_GRACEDOWN);
|
||||
usleep(CMDLONGDELAY);
|
||||
ser_send_pace(upsfd, UPSDELAY, "%s", timer);
|
||||
|
||||
ret = sdok();
|
||||
if (ret || cnt == 3)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* "tricky" part - we tried @nn variation and it (unsurprisingly)
|
||||
* failed; we have to abort the sequence with something bogus to have
|
||||
* the clean state; newer upses will respond with 'NO', older will be
|
||||
* silent (YMMV);
|
||||
*/
|
||||
ser_send_char(upsfd, APC_CMD_GRACEDOWN);
|
||||
usleep(UPSDELAY);
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* shutdown: K - delayed poweroff */
|
||||
static int sdcmd_K(int dummy)
|
||||
{
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
upsdebugx(1, "Issuing delayed poweroff");
|
||||
|
||||
ser_send_char(upsfd, APC_CMD_SHUTDOWN);
|
||||
usleep(CMDLONGDELAY);
|
||||
ser_send_char(upsfd, APC_CMD_SHUTDOWN);
|
||||
|
||||
return sdok();
|
||||
}
|
||||
|
||||
/* shutdown: Z - immediate poweroff */
|
||||
static int sdcmd_Z(int dummy)
|
||||
{
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
upsdebugx(1, "Issuing immediate poweroff");
|
||||
|
||||
ser_send_char(upsfd, APC_CMD_OFF);
|
||||
usleep(CMDLONGDELAY);
|
||||
ser_send_char(upsfd, APC_CMD_OFF);
|
||||
|
||||
return sdok();
|
||||
}
|
||||
|
||||
static int (*sdlist[])(int) = {
|
||||
sdcmd_S,
|
||||
sdcmd_ATn, /* for @nnn version */
|
||||
sdcmd_K,
|
||||
sdcmd_Z,
|
||||
sdcmd_CS,
|
||||
sdcmd_ATn, /* for @nn version */
|
||||
};
|
||||
|
||||
#define SDIDX_S 0
|
||||
#define SDIDX_AT3N 1
|
||||
#define SDIDX_K 2
|
||||
#define SDIDX_Z 3
|
||||
#define SDIDX_CS 4
|
||||
#define SDIDX_AT2N 5
|
||||
|
||||
#define SDCNT 6
|
||||
|
||||
static void upsdrv_shutdown_simple(int status)
|
||||
{
|
||||
unsigned int sdtype = 0;
|
||||
char *strval;
|
||||
|
||||
if ((strval = getval("sdtype"))) {
|
||||
errno = 0;
|
||||
sdtype = strtol(strval, NULL, 10);
|
||||
if (errno || sdtype < 0 || sdtype > 6)
|
||||
sdtype = 0;
|
||||
}
|
||||
|
||||
switch (sdtype) {
|
||||
|
||||
case 6: /* hard hibernate */
|
||||
sdcmd_ATn(3);
|
||||
break;
|
||||
case 5: /* "hack nn" hard hibernate */
|
||||
sdcmd_ATn(2);
|
||||
break;
|
||||
case 4: /* special hack for CS 350 and similar models */
|
||||
sdcmd_CS(status);
|
||||
break;
|
||||
|
||||
case 3: /* delayed poweroff */
|
||||
sdcmd_K(0);
|
||||
break;
|
||||
|
||||
case 2: /* instant poweroff */
|
||||
sdcmd_Z(0);
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
* Send a combined set of shutdown commands which can work
|
||||
* better if the UPS gets power during shutdown process
|
||||
* Specifically it sends both the soft shutdown 'S' and the
|
||||
* hard hibernate '@nnn' commands
|
||||
*/
|
||||
upsdebugx(1, "UPS - currently %s - sending soft/hard hibernate commands",
|
||||
(status & APC_STAT_OL) ? "on-line" : "on battery");
|
||||
|
||||
/* S works only when OB */
|
||||
if ((status & APC_STAT_OB) && sdcmd_S(0))
|
||||
break;
|
||||
sdcmd_ATn(3);
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* Send @nnn or S, depending on OB / OL status
|
||||
*/
|
||||
if (status & APC_STAT_OL) /* on line */
|
||||
sdcmd_ATn(3);
|
||||
else
|
||||
sdcmd_S(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void upsdrv_shutdown_advanced(int status)
|
||||
{
|
||||
const char *strval;
|
||||
const char deforder[] = {48 + SDIDX_S,
|
||||
48 + SDIDX_AT3N,
|
||||
48 + SDIDX_K,
|
||||
48 + SDIDX_Z,
|
||||
0};
|
||||
size_t i;
|
||||
int n;
|
||||
|
||||
strval = getval("advorder");
|
||||
|
||||
/* sanitize advorder */
|
||||
|
||||
if (!strval || !strlen(strval) || strlen(strval) > SDCNT)
|
||||
strval = deforder;
|
||||
for (i = 0; i < strlen(strval); i++) {
|
||||
if (strval[i] - 48 < 0 || strval[i] - 48 >= SDCNT) {
|
||||
strval = deforder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* try each method in the list with a little bit of handling in certain
|
||||
* cases
|
||||
*/
|
||||
|
||||
for (i = 0; i < strlen(strval); i++) {
|
||||
switch (strval[i] - 48) {
|
||||
case SDIDX_CS:
|
||||
n = status;
|
||||
break;
|
||||
case SDIDX_AT3N:
|
||||
n = 3;
|
||||
break;
|
||||
case SDIDX_AT2N:
|
||||
default:
|
||||
n = 2;
|
||||
}
|
||||
|
||||
if (sdlist[strval[i] - 48](n))
|
||||
break; /* finish if command succeeded */
|
||||
}
|
||||
}
|
||||
|
||||
/* power down the attached load immediately */
|
||||
void upsdrv_shutdown(void)
|
||||
{
|
||||
char temp[32];
|
||||
int ret, tval, sdtype = 0;
|
||||
int ret, status;
|
||||
|
||||
if (!smartmode())
|
||||
printf("Detection failed. Trying a shutdown command anyway.\n");
|
||||
upsdebugx(1, "SM detection failed. Trying a shutdown command anyway");
|
||||
|
||||
/* check the line status */
|
||||
|
||||
ret = ser_send_char(upsfd, APC_STATUS);
|
||||
|
||||
if (ret == 1) {
|
||||
ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR,
|
||||
ret = ser_get_line(upsfd, temp, sizeof(temp), ENDCHAR,
|
||||
IGNCHARS, SER_WAIT_SEC, SER_WAIT_USEC);
|
||||
|
||||
if (ret < 1) {
|
||||
printf("Status read failed! Assuming on battery state\n");
|
||||
tval = APC_STAT_LB | APC_STAT_OB;
|
||||
upsdebugx(1, "Status read failed ! Assuming on battery state");
|
||||
status = APC_STAT_LB | APC_STAT_OB;
|
||||
} else {
|
||||
tval = strtol(temp, 0, 16);
|
||||
status = strtol(temp, 0, 16);
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("Status request failed; assuming on battery state\n");
|
||||
tval = APC_STAT_LB | APC_STAT_OB;
|
||||
upsdebugx(1, "Status request failed; assuming on battery state");
|
||||
status = APC_STAT_LB | APC_STAT_OB;
|
||||
}
|
||||
|
||||
if (testvar("sdtype"))
|
||||
sdtype = atoi(getval("sdtype"));
|
||||
|
||||
switch (sdtype) {
|
||||
|
||||
case 4: /* special hack for CS 350 and similar models */
|
||||
printf("Using CS 350 'force OB' shutdown method\n");
|
||||
|
||||
if (tval & APC_STAT_OL) {
|
||||
printf("On line - forcing OB temporarily\n");
|
||||
ser_send_char(upsfd, 'U');
|
||||
}
|
||||
|
||||
ser_send_char(upsfd, 'S');
|
||||
break;
|
||||
|
||||
case 3: /* shutdown with grace period */
|
||||
printf("Sending delayed power off command to UPS\n");
|
||||
|
||||
ser_send_char(upsfd, APC_CMD_SHUTDOWN);
|
||||
usleep(CMDLONGDELAY);
|
||||
ser_send_char(upsfd, APC_CMD_SHUTDOWN);
|
||||
|
||||
break;
|
||||
|
||||
case 2: /* instant shutdown */
|
||||
printf("Sending power off command to UPS\n");
|
||||
|
||||
ser_send_char(upsfd, APC_CMD_OFF);
|
||||
usleep(CMDLONGDELAY);
|
||||
ser_send_char(upsfd, APC_CMD_OFF);
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
/* Send a combined set of shutdown commands which can work better */
|
||||
/* if the UPS gets power during shutdown process */
|
||||
/* Specifically it sends both the soft shutdown 'S' */
|
||||
/* and the powerdown after grace period - '@000' commands */
|
||||
printf("UPS - currently %s - sending shutdown/powerdown\n",
|
||||
(tval & APC_STAT_OL) ? "on-line" : "on battery");
|
||||
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
ser_send_pace(upsfd, UPSDELAY, "S@000");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* @000 - shutdown after 'p' grace period */
|
||||
/* - returns after 000 minutes (i.e. right away) */
|
||||
|
||||
/* S - shutdown after 'p' grace period, only on battery */
|
||||
/* returns after 'e' charge % plus 'r' seconds */
|
||||
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
|
||||
if (tval & APC_STAT_OL) { /* on line */
|
||||
printf("On line, sending shutdown+return command...\n");
|
||||
ser_send_pace(upsfd, UPSDELAY, "@000");
|
||||
}
|
||||
else {
|
||||
printf("On battery, sending normal shutdown command...\n");
|
||||
ser_send_char(upsfd, APC_CMD_SOFTDOWN);
|
||||
}
|
||||
}
|
||||
if (testvar("advorder") && strcasecmp(getval("advorder"), "no"))
|
||||
upsdrv_shutdown_advanced(status);
|
||||
else
|
||||
upsdrv_shutdown_simple(status);
|
||||
}
|
||||
|
||||
/* 940-0095B support: set DTR, lower RTS */
|
||||
|
@ -921,6 +1107,7 @@ static int setvar_enum(apc_vartab_t *vt, const char *val)
|
|||
char orig[256], temp[256];
|
||||
const char *ptr;
|
||||
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
ret = ser_send_char(upsfd, vt->cmd);
|
||||
|
||||
if (ret != 1) {
|
||||
|
@ -1015,7 +1202,6 @@ static int setvar_string(apc_vartab_t *vt, const char *val)
|
|||
char temp[256];
|
||||
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
|
||||
ret = ser_send_char(upsfd, vt->cmd);
|
||||
|
||||
if (ret != 1) {
|
||||
|
@ -1118,6 +1304,7 @@ static int do_cmd(apc_cmdtab_t *ct)
|
|||
int ret;
|
||||
char buf[SMALLBUF];
|
||||
|
||||
ser_flush_in(upsfd, IGNCHARS, nut_debug_level);
|
||||
ret = ser_send_char(upsfd, ct->cmd);
|
||||
|
||||
if (ret != 1) {
|
||||
|
@ -1222,7 +1409,9 @@ static void setuphandlers(void)
|
|||
void upsdrv_makevartable(void)
|
||||
{
|
||||
addvar(VAR_VALUE, "cable", "Specify alternate cable (940-0095B)");
|
||||
addvar(VAR_VALUE, "sdtype", "Specify shutdown type (1-3)");
|
||||
addvar(VAR_VALUE, "wugrace", "Hard hibernate's wakeup grace");
|
||||
addvar(VAR_VALUE, "sdtype", "Specify simple shutdown method (0-6)");
|
||||
addvar(VAR_VALUE, "advorder", "Enable advanced shutdown control");
|
||||
}
|
||||
|
||||
void upsdrv_initups(void)
|
||||
|
@ -1234,9 +1423,8 @@ void upsdrv_initups(void)
|
|||
|
||||
cable = getval("cable");
|
||||
|
||||
if (cable)
|
||||
if (!strcasecmp(cable, ALT_CABLE_1))
|
||||
init_serial_0095B();
|
||||
if (cable && !strcasecmp(cable, ALT_CABLE_1))
|
||||
init_serial_0095B();
|
||||
|
||||
/* make sure we wake up if the UPS sends alert chars to us */
|
||||
extrafd = upsfd;
|
||||
|
@ -1244,18 +1432,12 @@ void upsdrv_initups(void)
|
|||
|
||||
void upsdrv_help(void)
|
||||
{
|
||||
printf("\nShutdown types:\n");
|
||||
printf(" 0: soft shutdown or powerdown, depending on battery status\n");
|
||||
printf(" 1: soft shutdown followed by powerdown\n");
|
||||
printf(" 2: instant power off\n");
|
||||
printf(" 3: power off with grace period\n");
|
||||
printf(" 4: 'force OB' hack method for CS 350\n");
|
||||
printf("Modes 0-1 will make the UPS come back when power returns\n");
|
||||
printf("Modes 2-3 will make the UPS stay turned off when power returns\n");
|
||||
}
|
||||
|
||||
void upsdrv_initinfo(void)
|
||||
{
|
||||
const char *pmod, *pser;
|
||||
|
||||
if (!smartmode()) {
|
||||
fatalx(EXIT_FAILURE,
|
||||
"Unable to detect an APC Smart protocol UPS on port %s\n"
|
||||
|
@ -1268,8 +1450,12 @@ void upsdrv_initinfo(void)
|
|||
|
||||
getbaseinfo();
|
||||
|
||||
printf("Detected %s [%s] on %s\n", dstate_getinfo("ups.model"),
|
||||
dstate_getinfo("ups.serial"), device_path);
|
||||
if (!(pmod = dstate_getinfo("ups.model")))
|
||||
pmod = "\"unknown model\"";
|
||||
if (!(pser = dstate_getinfo("ups.serial")))
|
||||
pser = "unknown serial";
|
||||
|
||||
upsdebugx(1, "Detected %s [%s] on %s", pmod, pser, device_path);
|
||||
|
||||
setuphandlers();
|
||||
}
|
||||
|
|
|
@ -23,20 +23,22 @@
|
|||
#include "serial.h"
|
||||
#include "timehead.h"
|
||||
|
||||
#define APC_TABLE_VERSION "version 2.1"
|
||||
#define APC_TABLE_VERSION "version 2.2"
|
||||
|
||||
/* Basic UPS reply line structure */
|
||||
#define ENDCHAR 10 /* APC ends responses with LF */
|
||||
|
||||
/* these two are only used during startup */
|
||||
#define IGNCHARS "\015+$|!~%?=*#&" /* special characters to ignore */
|
||||
/* characters ignored by default */
|
||||
#define IGNCHARS "\015+$|!~%?=#&" /* special characters to ignore */
|
||||
|
||||
/* these one is used only during startup, due to ^Z sending certain characters such as # */
|
||||
#define MINIGNCHARS "\015+$|!" /* minimum set of special characters to ignore */
|
||||
|
||||
/* normal polls: characters we don't want to parse (including a few alerts) */
|
||||
#define POLL_IGNORE "\015?=*&|"
|
||||
#define POLL_IGNORE "\015&|"
|
||||
|
||||
/* alert characters we care about - OL, OB, LB, not LB, RB */
|
||||
#define POLL_ALERT "$!%+#"
|
||||
/* alert characters we care about - OL, OB, LB, not LB, RB, OVER, not OVER */
|
||||
#define POLL_ALERT "$!%+#?="
|
||||
|
||||
#define UPSDELAY 50000 /* slow down multicharacter commands */
|
||||
#define CMDLONGDELAY 1500000 /* some commands need a 1.5s gap for safety */
|
||||
|
@ -77,7 +79,6 @@
|
|||
/* Driver command table flag values */
|
||||
|
||||
#define APC_POLL 0x0001 /* Poll this variable regularly */
|
||||
#define APC_IGNORE 0x0002 /* Never poll this */
|
||||
#define APC_PRESENT 0x0004 /* Capability seen on this UPS */
|
||||
|
||||
#define APC_RW 0x0010 /* read-write variable */
|
||||
|
@ -109,15 +110,11 @@ typedef struct {
|
|||
|
||||
apc_vartab_t apc_vartab[] = {
|
||||
|
||||
{ "ups.firmware.old", 0, 'V' },
|
||||
{ "ups.firmware", 0, 'b' },
|
||||
{ "ups.firmware.aux", 0, 'v' },
|
||||
{ "ups.model", 0, 0x01 },
|
||||
|
||||
/* FUTURE: depends on variable naming scheme */
|
||||
#if 0
|
||||
{ "ups.model.code", 0, 'V' },
|
||||
#endif
|
||||
|
||||
{ "ups.serial", 0, 'n' },
|
||||
{ "ups.mfr.date", 0, 'm' },
|
||||
|
||||
|
@ -207,6 +204,7 @@ apc_vartab_t apc_vartab[] = {
|
|||
#define APC_CMD_CALTOGGLE 'D'
|
||||
#define APC_CMD_SHUTDOWN 'K'
|
||||
#define APC_CMD_SOFTDOWN 'S'
|
||||
#define APC_CMD_GRACEDOWN '@'
|
||||
#define APC_CMD_SIMPWF 'U'
|
||||
#define APC_CMD_BTESTTOGGLE 'W'
|
||||
#define APC_CMD_OFF 'Z'
|
||||
|
@ -232,6 +230,8 @@ apc_cmdtab_t apc_cmdtab[] =
|
|||
{ "test.battery.start", 0, APC_CMD_BTESTTOGGLE },
|
||||
{ "test.battery.stop", 0, APC_CMD_BTESTTOGGLE },
|
||||
|
||||
{ "shutdown.return.grace",
|
||||
APC_NASTY, APC_CMD_GRACEDOWN },
|
||||
{ "shutdown.return", APC_NASTY, APC_CMD_SOFTDOWN },
|
||||
{ "shutdown.stayoff", APC_NASTY|APC_REPEAT, APC_CMD_SHUTDOWN },
|
||||
|
||||
|
@ -244,9 +244,6 @@ apc_cmdtab_t apc_cmdtab[] =
|
|||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
/* things to ignore in protocol_verify - useless variables, etc. */
|
||||
#define CMD_IGN_CHARS "\032-78@.,~\047\177QHRTYayz)1IJ"
|
||||
|
||||
/* compatibility with hardware that doesn't do APC_CMDSET ('a') */
|
||||
|
||||
struct {
|
||||
|
@ -255,33 +252,40 @@ struct {
|
|||
int flags;
|
||||
} compat_tab[] = {
|
||||
/* APC Matrix */
|
||||
{ "0XI", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0XM", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0ZI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5UI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5ZM", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
/* APC600 */
|
||||
{ "6QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900 */
|
||||
{ "7QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 1250. */
|
||||
{ "7QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900I */
|
||||
{ "7II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 2000I */
|
||||
{ "9II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
{ "9GI", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 1250 */
|
||||
{ "8QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* CS 350 */
|
||||
{ "5.4.D", "\1ABPQRSUYbdfgjmnx9", 0 },
|
||||
/* Smart-UPS 600 */
|
||||
{ "D9", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D8", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D7", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D6", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D5", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D4", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D9", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D8", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D7", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D6", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D5", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D4", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
|
||||
{ NULL, NULL, 0 },
|
||||
};
|
||||
|
|
|
@ -120,7 +120,7 @@ TODO List:
|
|||
#include "bcmxcp.h"
|
||||
|
||||
#define DRIVER_NAME "BCMXCP UPS driver"
|
||||
#define DRIVER_VERSION "0.23"
|
||||
#define DRIVER_VERSION "0.24"
|
||||
|
||||
/* driver description structure */
|
||||
upsdrv_info_t upsdrv_info = {
|
||||
|
@ -1176,17 +1176,20 @@ void upsdrv_initinfo(void)
|
|||
iIndex += 1;
|
||||
|
||||
/* Size of command list block */
|
||||
cmd_list_len = get_word(answer+iIndex);
|
||||
if (iIndex < res)
|
||||
cmd_list_len = get_word(answer+iIndex);
|
||||
upsdebugx(2, "Length of command list: %d\n", cmd_list_len);
|
||||
iIndex += 2;
|
||||
|
||||
/* Size of outlet monitoring block */
|
||||
outlet_block_len = get_word(answer+iIndex);
|
||||
if (iIndex < res)
|
||||
outlet_block_len = get_word(answer+iIndex);
|
||||
upsdebugx(2, "Length of outlet_block: %d\n", outlet_block_len);
|
||||
iIndex += 2;
|
||||
|
||||
/* Size of the alarm block */
|
||||
alarm_block_len = get_word(answer+iIndex);
|
||||
if (iIndex < res)
|
||||
alarm_block_len = get_word(answer+iIndex);
|
||||
upsdebugx(2, "Length of alarm_block: %d\n", alarm_block_len);
|
||||
/* End of UPS ID block request */
|
||||
|
||||
|
@ -1209,7 +1212,8 @@ void upsdrv_initinfo(void)
|
|||
init_limit();
|
||||
|
||||
/* Get information on UPS commands */
|
||||
init_command_map();
|
||||
if (cmd_list_len)
|
||||
init_command_map();
|
||||
|
||||
/* FIXME: leave up to init_command_map() to add instant commands? */
|
||||
dstate_addcmd("shutdown.return");
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#define PW_MAX_BAUD 5
|
||||
|
||||
#define SUBDRIVER_NAME "RS-232 communication subdriver"
|
||||
#define SUBDRIVER_VERSION "0.17"
|
||||
#define SUBDRIVER_VERSION "0.18"
|
||||
|
||||
/* communication driver description structure */
|
||||
upsdrv_info_t comm_upsdrv_info = {
|
||||
|
@ -47,8 +47,10 @@ static void send_command(unsigned char *command, int command_length)
|
|||
|
||||
while (retry++ < PW_MAX_TRY) {
|
||||
|
||||
if (retry == PW_MAX_TRY)
|
||||
if (retry == PW_MAX_TRY) {
|
||||
ser_send_char(upsfd, 0x1d); /* last retry is preceded by a ESC.*/
|
||||
usleep(250000);
|
||||
}
|
||||
|
||||
sent = ser_send_buf(upsfd, sbuf, command_length);
|
||||
|
||||
|
@ -82,7 +84,7 @@ int get_answer(unsigned char *data, unsigned char command)
|
|||
res = ser_get_char(upsfd, my_buf, 1, 0);
|
||||
|
||||
if (res != 1) {
|
||||
upsdebugx(1,"Receive error (PW_COMMAND_START_BYTE): %d!!!\n", res);
|
||||
upsdebugx(1,"Receive error (PW_COMMAND_START_BYTE): %d, cmd=%x!!!\n", res, command);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -250,6 +252,7 @@ void upsdrv_comm_good()
|
|||
void pw_comm_setup(const char *port)
|
||||
{
|
||||
unsigned char command = PW_SET_REQ_ONLY_MODE;
|
||||
unsigned char id_command = PW_ID_BLOCK_REQ;
|
||||
unsigned char answer[256];
|
||||
int i = 0, baud, mybaud = 0, ret = -1;
|
||||
|
||||
|
@ -274,6 +277,10 @@ void pw_comm_setup(const char *port)
|
|||
send_write_command(AUT, 4);
|
||||
usleep(500000);
|
||||
ret = command_sequence(&command, 1, answer);
|
||||
if (ret <= 0) {
|
||||
usleep(500000);
|
||||
ret = command_sequence(&id_command, 1, answer);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
upslogx(LOG_INFO, "Connected to UPS on %s with baudrate %d", port, baud);
|
||||
|
@ -293,6 +300,10 @@ void pw_comm_setup(const char *port)
|
|||
send_write_command(AUT, 4);
|
||||
usleep(500000);
|
||||
ret = command_sequence(&command, 1, answer);
|
||||
if (ret <= 0) {
|
||||
usleep(500000);
|
||||
ret = command_sequence(&id_command, 1, answer);
|
||||
}
|
||||
|
||||
if (ret > 0) {
|
||||
upslogx(LOG_INFO, "Connected to UPS on %s with baudrate %d", port, pw_baud_rates[i].name);
|
||||
|
|
|
@ -160,7 +160,7 @@ int get_answer(unsigned char *data, unsigned char command)
|
|||
{
|
||||
/* Clear any possible endpoint stalls */
|
||||
usb_clear_halt(upsdev, 0x81);
|
||||
//continue; // FIXME: seems a break would be better!
|
||||
/* continue; */ /* FIXME: seems a break would be better! */
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ static int blazer_status(const char *cmd)
|
|||
* 01234567890123456789012345678901234567890123456
|
||||
* 0 1 2 3 4
|
||||
*/
|
||||
if (blazer_command(cmd, buf, sizeof(buf)) < 47) {
|
||||
if (blazer_command(cmd, buf, sizeof(buf)) < 46) {
|
||||
upsdebugx(2, "%s: short reply", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
@ -691,6 +691,9 @@ void upsdrv_updateinfo(void)
|
|||
if (blazer_status(command[proto].status)) {
|
||||
|
||||
if (retry < MAXTRIES) {
|
||||
upsdebugx(1, "Communications with UPS lost: status read failed!");
|
||||
retry++;
|
||||
} else if (retry == MAXTRIES) {
|
||||
upslogx(LOG_WARNING, "Communications with UPS lost: status read failed!");
|
||||
retry++;
|
||||
} else {
|
||||
|
@ -723,7 +726,7 @@ void upsdrv_updateinfo(void)
|
|||
lastpoll = now;
|
||||
}
|
||||
|
||||
if (retry) {
|
||||
if (retry > MAXTRIES) {
|
||||
upslogx(LOG_NOTICE, "Communications with UPS re-established");
|
||||
}
|
||||
|
||||
|
|
|
@ -255,16 +255,17 @@ static int krauler_command(const char *cmd, char *buf, size_t buflen)
|
|||
|
||||
/* "UPS No Ack" has a special meaning */
|
||||
if (!strcasecmp(buf, "UPS No Ack")) {
|
||||
upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Replace the first byte of what we received with the correct one */
|
||||
buf[0] = command[i].prefix;
|
||||
|
||||
upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
upsdebugx(3, "read: %.*s", (int)strcspn(buf, "\r"), buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -295,13 +296,21 @@ static void *krauler_subdriver(void)
|
|||
}
|
||||
|
||||
|
||||
static void *phoenix_subdriver(void)
|
||||
{
|
||||
subdriver_command = &phoenix_command;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static usb_device_id_t blazer_usb_id[] = {
|
||||
{ USB_DEVICE(0x05b8, 0x0000), &cypress_subdriver }, /* Agiler UPS */
|
||||
{ USB_DEVICE(0x0001, 0x0000), &krauler_subdriver }, /* Krauler UP-M500VA */
|
||||
{ USB_DEVICE(0xffff, 0x0000), &krauler_subdriver }, /* Ablerex 625L USB */
|
||||
{ 0x0001, 0x0000, &krauler_subdriver }, /* Krauler UP-M500VA */
|
||||
{ 0xffff, 0x0000, &krauler_subdriver }, /* Ablerex 625L USB */
|
||||
{ USB_DEVICE(0x0665, 0x5161), &cypress_subdriver }, /* Belkin F6C1200-UNV */
|
||||
{ USB_DEVICE(0x06da, 0x0003), &ippon_subdriver }, /* Mustek Powermust */
|
||||
{ USB_DEVICE(0x0f03, 0x0001), &cypress_subdriver }, /* Unitek Alpha 1200Sx */
|
||||
{ USB_DEVICE(0x14f0, 0x00c9), &phoenix_subdriver }, /* GE EP series */
|
||||
/* end of list */
|
||||
{-1, -1, NULL}
|
||||
};
|
||||
|
|
|
@ -74,6 +74,22 @@ static info_lkp_t cps_battvolt[] = {
|
|||
{ 0, NULL, &cps_battvolt_fun }
|
||||
};
|
||||
|
||||
/* returns statically allocated string - must not use it again before
|
||||
done with result! */
|
||||
static const char *cps_battcharge_fun(double value)
|
||||
{
|
||||
static char buf[8];
|
||||
|
||||
/* clamp battery charge to 100% */
|
||||
snprintf(buf, sizeof(buf), "%.0f", value < 100.0 ? value : 100.0);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static info_lkp_t cps_battcharge[] = {
|
||||
{ 0, NULL, &cps_battcharge_fun }
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* Vendor-specific usage table */
|
||||
/* --------------------------------------------------------------- */
|
||||
|
@ -106,7 +122,7 @@ static hid_info_t cps_hid2nut[] = {
|
|||
{ "battery.mfr.date", 0, 0, "UPS.PowerSummary.iOEMInformation", NULL, "%s", 0, stringid_conversion },
|
||||
{ "battery.charge.warning", 0, 0, "UPS.PowerSummary.WarningCapacityLimit", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%s", 0, cps_battcharge },
|
||||
{ "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "battery.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.0f", 0, NULL },
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
#include "state.h"
|
||||
#include "parseconf.h"
|
||||
|
||||
static int sockfd = -1, stale = 1, alarm_active = 0;
|
||||
static int sockfd = -1, stale = 1, alarm_active = 0, ignorelb = 0;
|
||||
static char *sockfn = NULL;
|
||||
static char status_buf[ST_MAX_VALUE_LEN], alarm_buf[ST_MAX_VALUE_LEN];
|
||||
static st_tree_t *dtree_root = NULL;
|
||||
|
@ -223,8 +223,11 @@ static void sock_connect(int sock)
|
|||
int fd, ret;
|
||||
conn_t *conn;
|
||||
struct sockaddr_un sa;
|
||||
#if defined(__hpux) && !defined(_XOPEN_SOURCE_EXTENDED)
|
||||
int salen;
|
||||
#else
|
||||
socklen_t salen;
|
||||
|
||||
#endif
|
||||
salen = sizeof(sa);
|
||||
fd = accept(sock, (struct sockaddr *) &sa, &salen);
|
||||
|
||||
|
@ -639,7 +642,12 @@ void dstate_setflags(const char *var, int flags)
|
|||
sttmp = state_tree_find(dtree_root, var);
|
||||
|
||||
if (!sttmp) {
|
||||
upslogx(LOG_ERR, "dstate_setflags: base variable (%s) does not exist", var);
|
||||
upslogx(LOG_ERR, "%s: base variable (%s) does not exist", __func__, var);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sttmp->flags & ST_FLAG_IMMUTABLE) {
|
||||
upslogx(LOG_WARNING, "%s: base variable (%s) is immutable", __func__, var);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -792,12 +800,21 @@ int dstate_is_stale(void)
|
|||
/* clean out the temp space for a new pass */
|
||||
void status_init(void)
|
||||
{
|
||||
if (dstate_getinfo("driver.flag.ignorelb")) {
|
||||
ignorelb = 1;
|
||||
}
|
||||
|
||||
memset(status_buf, 0, sizeof(status_buf));
|
||||
}
|
||||
|
||||
/* add a status element */
|
||||
void status_set(const char *buf)
|
||||
{
|
||||
if (ignorelb && !strcasecmp(buf, "LB")) {
|
||||
upsdebugx(2, "%s: ignoring LB flag from device", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* separate with a space if multiple elements are present */
|
||||
if (strlen(status_buf) > 0) {
|
||||
snprintfcat(status_buf, sizeof(status_buf), " %s", buf);
|
||||
|
@ -809,6 +826,31 @@ void status_set(const char *buf)
|
|||
/* write the status_buf into the externally visible dstate storage */
|
||||
void status_commit(void)
|
||||
{
|
||||
while (ignorelb) {
|
||||
const char *val, *low;
|
||||
|
||||
val = dstate_getinfo("battery.charge");
|
||||
low = dstate_getinfo("battery.charge.low");
|
||||
|
||||
if (val && low && (strtol(val, NULL, 10) < strtol(low, NULL, 10))) {
|
||||
snprintfcat(status_buf, sizeof(status_buf), " LB");
|
||||
upsdebugx(2, "%s: appending LB flag [charge '%s' below '%s']", __func__, val, low);
|
||||
break;
|
||||
}
|
||||
|
||||
val = dstate_getinfo("battery.runtime");
|
||||
low = dstate_getinfo("battery.runtime.low");
|
||||
|
||||
if (val && low && (strtol(val, NULL, 10) < strtol(low, NULL, 10))) {
|
||||
snprintfcat(status_buf, sizeof(status_buf), " LB");
|
||||
upsdebugx(2, "%s: appending LB flag [runtime '%s' below '%s']", __func__, val, low);
|
||||
break;
|
||||
}
|
||||
|
||||
/* LB condition not detected */
|
||||
break;
|
||||
}
|
||||
|
||||
if (alarm_active) {
|
||||
dstate_setinfo("ups.status", "ALARM %s", status_buf);
|
||||
} else {
|
||||
|
|
|
@ -375,7 +375,7 @@ static int is_valid_data(const char* varname)
|
|||
* enforcing controls! We also need a way to automate
|
||||
* the update / sync process (with cmdvartab?!) */
|
||||
|
||||
upsdebugx(1, "Unknown data. Commiting anyway...");
|
||||
upsdebugx(1, "Unknown data. Committing anyway...");
|
||||
return 1;
|
||||
/* return 0;*/
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ static int is_valid_value(const char* varname, const char *value)
|
|||
* enforcing controls! We also need a way to automate
|
||||
* the update / sync process (with cmdvartab?) */
|
||||
|
||||
upsdebugx(1, "Unknown data. Commiting value anyway...");
|
||||
upsdebugx(1, "Unknown data. Committing value anyway...");
|
||||
return 1;
|
||||
/* return 0;*/
|
||||
}
|
||||
|
@ -412,7 +412,7 @@ static void upsconf_err(const char *errmsg)
|
|||
static int parse_data_file(int upsfd)
|
||||
{
|
||||
char fn[SMALLBUF];
|
||||
char *ptr, *var_value = (char*) xmalloc(MAX_STRING_SIZE);
|
||||
char *ptr, var_value[MAX_STRING_SIZE];
|
||||
int value_args = 0, counter;
|
||||
time_t now;
|
||||
|
||||
|
@ -501,13 +501,13 @@ static int parse_data_file(int upsfd)
|
|||
}
|
||||
else
|
||||
{
|
||||
memset(var_value, 0, MAX_STRING_SIZE);
|
||||
for (counter = 1, value_args = ctx->numargs ;
|
||||
counter < value_args ; counter++)
|
||||
{
|
||||
if (counter != 1) /* don't append the first space separator */
|
||||
strncat(var_value, " ", 1);
|
||||
strncat(var_value, ctx->arglist[counter], MAX_STRING_SIZE);
|
||||
if (counter == 1) /* don't append the first space separator */
|
||||
snprintf(var_value, sizeof(var_value), "%s", ctx->arglist[counter]);
|
||||
else
|
||||
snprintfcat(var_value, sizeof(var_value), " %s", ctx->arglist[counter]);
|
||||
}
|
||||
|
||||
if (setvar(ctx->arglist[0], var_value) == STAT_SET_UNKNOWN)
|
||||
|
@ -529,7 +529,6 @@ static int parse_data_file(int upsfd)
|
|||
pconf_finish(ctx);
|
||||
free(ctx);
|
||||
ctx=NULL;
|
||||
free(var_value);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eaton-mib.c - data to monitor Eaton Aphel PDUs (Basic and Complex)
|
||||
*
|
||||
* Copyright (C) 2008
|
||||
* Copyright (C) 2008 - 2010
|
||||
* Arnaud Quette <ArnaudQuette@Eaton.com>
|
||||
*
|
||||
* Sponsored by Eaton <http://www.eaton.com>
|
||||
|
@ -25,7 +25,7 @@
|
|||
|
||||
#include "eaton-mib.h"
|
||||
|
||||
#define EATON_APHEL_MIB_VERSION "0.4"
|
||||
#define EATON_APHEL_MIB_VERSION "0.45"
|
||||
|
||||
/* APHEL-GENESIS-II-MIB (monitored ePDU)
|
||||
* *************************************
|
||||
|
@ -87,8 +87,6 @@ static snmp_info_t eaton_aphel_genesisII_mib[] = {
|
|||
|
||||
#define APHEL2_OID_MODEL_NAME AR_OID_MODEL_NAME
|
||||
|
||||
/* Common Aphel / Raritan declaration */
|
||||
|
||||
#define AR_OID_MODEL_NAME AR_BASE_OID ".1.1.12.0"
|
||||
#define AR_OID_DEVICE_NAME AR_BASE_OID ".1.1.13.0"
|
||||
#define AR_OID_FIRMREV AR_BASE_OID ".1.1.1.0"
|
||||
|
@ -180,12 +178,21 @@ static snmp_info_t eaton_aphel_revelation_mib[] = {
|
|||
|
||||
/* FIXME:
|
||||
* - delay for startup/shutdown sequence
|
||||
* - support for Ambient page
|
||||
temperatureSensorCount" src="snmp:$sysoid.2.1.0
|
||||
ambient.temperature src="snmp:$sysoid.2.2.1.3.$indiceSensor => seems dumb!
|
||||
ambient.humidity src="snmp:$sysoid.2.4.1.3.$indiceSensor
|
||||
* - support for multiple Ambient sensors ( max. 8), starting at index '0'
|
||||
* ambient.%i.temperature => .1.3.6.1.4.1.534.6.6.6.2.2.1.3.%i
|
||||
* ambient.%i.humidity => .1.3.6.1.4.1.534.6.6.6.2.4.1.3.%i
|
||||
*/
|
||||
|
||||
/* Ambient page */
|
||||
/* We use critical levels, for both temperature and humidity,
|
||||
* since warning levels are also available! */
|
||||
{ "ambient.temperature", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.2.1.3.0", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.temperature.low", 0, 1.0, "1.3.6.1.4.1.534.6.6.6.2.2.1.6.0", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.temperature.high", 0, 1.0, "1.3.6.1.4.1.534.6.6.6.2.2.1.7.0", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.humidity", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.4.1.3.0", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.humidity.low", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.4.1.6.0", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.humidity.high", 0, 1.0, ".1.3.6.1.4.1.534.6.6.6.2.4.1.7.0", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
|
||||
/* instant commands. */
|
||||
/* Note that load.cycle might be replaced by / mapped on shutdown.reboot */
|
||||
/* no counterpart found!
|
||||
|
|
|
@ -142,12 +142,12 @@ void upsdrv_initinfo(void)
|
|||
*/
|
||||
if ((v = getval("OL")) != NULL) {
|
||||
parse_input_signals(v, &upstab[upstype].line_ol, &upstab[upstype].val_ol);
|
||||
upsdebugx(2, "parse_input_signals: OL overriden with %s\n", v);
|
||||
upsdebugx(2, "parse_input_signals: OL overridden with %s\n", v);
|
||||
}
|
||||
|
||||
if ((v = getval("LB")) != NULL) {
|
||||
parse_input_signals(v, &upstab[upstype].line_bl, &upstab[upstype].val_bl);
|
||||
upsdebugx(2, "parse_input_signals: LB overriden with %s\n", v);
|
||||
upsdebugx(2, "parse_input_signals: LB overridden with %s\n", v);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,12 +318,12 @@ void upsdrv_initups(void)
|
|||
*/
|
||||
if ((v = getval("CP")) != NULL) {
|
||||
parse_output_signals(v, &upstab[upstype].line_norm);
|
||||
upsdebugx(2, "parse_output_signals: CP overriden with %s\n", v);
|
||||
upsdebugx(2, "parse_output_signals: CP overridden with %s\n", v);
|
||||
}
|
||||
|
||||
if ((v = getval("SD")) != NULL) {
|
||||
parse_output_signals(v, &upstab[upstype].line_sd);
|
||||
upsdebugx(2, "parse_output_signals: SD overriden with %s\n", v);
|
||||
upsdebugx(2, "parse_output_signals: SD overridden with %s\n", v);
|
||||
}
|
||||
|
||||
if (ioctl(upsfd, TIOCMSET, &upstab[upstype].line_norm)) {
|
||||
|
|
|
@ -141,7 +141,6 @@ static int refresh_report_buffer(reportbuf_t *rbuf, hid_dev_handle_t udev, HIDDa
|
|||
{
|
||||
int id = pData->ReportID;
|
||||
int r;
|
||||
unsigned char buf[SMALLBUF];
|
||||
|
||||
if (rbuf->ts[id] + age > time(NULL)) {
|
||||
/* buffered report is still good; nothing to do */
|
||||
|
@ -149,17 +148,14 @@ static int refresh_report_buffer(reportbuf_t *rbuf, hid_dev_handle_t udev, HIDDa
|
|||
return 0;
|
||||
}
|
||||
|
||||
r = comm_driver->get_report(udev, id, buf, sizeof(buf));
|
||||
r = comm_driver->get_report(udev, id, rbuf->data[id], rbuf->len[id]);
|
||||
if (r <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* broken report descriptors are common, so store whatever we can */
|
||||
memcpy(rbuf->data[id], buf, (r < rbuf->len[id]) ? r : rbuf->len[id]);
|
||||
|
||||
if (rbuf->len[id] != r) {
|
||||
upsdebugx(2, "%s: expected %d bytes, but got %d instead", __func__, rbuf->len[id], r);
|
||||
upsdebug_hex(3, "Report[err]", buf, r);
|
||||
upsdebug_hex(3, "Report[err]", rbuf->data[id], r);
|
||||
} else {
|
||||
upsdebug_hex(3, "Report[get]", rbuf->data[id], rbuf->len[id]);
|
||||
}
|
||||
|
@ -399,7 +395,7 @@ char *HIDGetIndexString(hid_dev_handle_t udev, const int Index, char *buf, size_
|
|||
if (comm_driver->get_string(udev, Index, buf, buflen) < 1)
|
||||
buf[0] = '\0';
|
||||
|
||||
return buf;
|
||||
return rtrim(buf, '\n');
|
||||
}
|
||||
|
||||
/* Return pointer to indexed string from HID path (empty if not found)
|
||||
|
|
|
@ -23,8 +23,58 @@
|
|||
#include "timehead.h"
|
||||
#include "nut_stdint.h"
|
||||
|
||||
#define sivann
|
||||
#define IsBitSet(val, bit) ((val) & (1 << (bit)))
|
||||
|
||||
#define DRIVER_NAME "Liebert ESP-II serial UPS driver"
|
||||
#define DRIVER_VERSION "0.02"
|
||||
#define DRIVER_VERSION "0.03"
|
||||
#define UPS_SHUTDOWN_DELAY 12 /* it means UPS will be shutdown 120 sec */
|
||||
#define SHUTDOWN_CMD_LEN 8
|
||||
|
||||
/* values for sending to UPS */
|
||||
enum mult_enum {
|
||||
M_10,
|
||||
M_0_1,
|
||||
M_VOLTAGE_I,
|
||||
M_VOLTAGE_O,
|
||||
M_VOLTAGE_B,
|
||||
M_CURRENT_I,
|
||||
M_CURRENT_O,
|
||||
M_CURRENT_B,
|
||||
M_LOAD_VA,
|
||||
M_LOAD_WATT,
|
||||
M_FREQUENCY,
|
||||
M_VOLT_DC,
|
||||
M_TEMPERATURE,
|
||||
M_CURRENT_DC ,
|
||||
M_BAT_RUNTIME,
|
||||
M_NOMPOWER,
|
||||
M_POWER,
|
||||
M_REALPOWER,
|
||||
M_LOADPERC
|
||||
};
|
||||
|
||||
static float multi[19]={
|
||||
10.0,
|
||||
0.1,
|
||||
0.1, /* volt */
|
||||
0.1,
|
||||
0.1,
|
||||
0.1, /* curr */
|
||||
0.1,
|
||||
0.1,
|
||||
100.0, /* va */
|
||||
100.0, /* W */
|
||||
0.01, /* FREQ */
|
||||
0.1, /* V DC*/
|
||||
0.1, /* TEMP*/
|
||||
0.01, /* CUR DC*/
|
||||
60.0, /* BAT RUNTIME*/
|
||||
100.0, /* NOMPOWER*/
|
||||
100.0, /* POWER*/
|
||||
100.0, /* REAL POWER*/
|
||||
1.0 /* LOADPERC*/
|
||||
};
|
||||
|
||||
static int instcmd(const char *cmdname, const char *extra);
|
||||
static int setvar(const char *varname, const char *val);
|
||||
|
@ -33,7 +83,8 @@ static int setvar(const char *varname, const char *val);
|
|||
upsdrv_info_t upsdrv_info = {
|
||||
DRIVER_NAME,
|
||||
DRIVER_VERSION,
|
||||
"Richard Gregory <r.gregory liv ac uk>",
|
||||
"Richard Gregory <r.gregory liv ac uk>\n" \
|
||||
"Robert Jobbagy <jobbagy.robert at gmail dot com",
|
||||
DRV_EXPERIMENTAL,
|
||||
{ NULL }
|
||||
};
|
||||
|
@ -46,7 +97,17 @@ static const unsigned char
|
|||
cmd_bitfield3[] = { 1,148,2,1,3,155 }, /* CHECK_AIR_FILTER (10), BAD_BYPASS_PWR (8), OUTPUT_OVERVOLTAGE (7), OUTPUT_UNDERVOLTAGE (6), LOW_BATTERY (5), CHARGER_FAIL (3), SHUTDOWN_PENDING (2), BAD_INPUT_FREQ (1), UPS_OVERLOAD (0) */
|
||||
cmd_bitfield7[] = { 1,148,2,1,7,159 }, /* AMBIENT_OVERTEMP (2) */
|
||||
cmd_battestres[] = { 1,148,2,1,12,164 }, /* BATTERY_TEST_RESULT */
|
||||
cmd_selftestres[] = { 1,148,2,1,13,165 }; /* SELF_TEST_RESULT */
|
||||
cmd_selftestres[] = { 1,148,2,1,13,165 }, /* SELF_TEST_RESULT */
|
||||
cmd_upstype[] = { 1,136,2,1,1,141}, /* type bits + number of phases in bit groups*/
|
||||
cmd_scaling1[] = { 1,131,2,1,2,137}, /* part of multiplier information*/
|
||||
|
||||
/* Shutdown commands by Robert Jobbagy */
|
||||
cmd_setOutOffMode[] = { 1,156,4,1,6,0,1,169}, /* UPS OutOffMode command */
|
||||
cmd_setOutOffDelay[] = {1,156,4,1,5,0,UPS_SHUTDOWN_DELAY,167+UPS_SHUTDOWN_DELAY}, /* UPS Shutdown with delay */
|
||||
cmd_sysLoadKey[] = {1,156,2,1,7,167}, /* UPS SysLoadKey */
|
||||
cmd_shutdown[] = {1,156,4,1,136,76,76,194}; /* UPS shutdown */
|
||||
|
||||
static int num_inphases = 1, num_outphases = 1;
|
||||
|
||||
static char cksum(const char *buf, const size_t len)
|
||||
{
|
||||
|
@ -60,22 +121,22 @@ static char cksum(const char *buf, const size_t len)
|
|||
return sum;
|
||||
}
|
||||
|
||||
static int do_command(const unsigned char *command, char *reply)
|
||||
static int do_command(const unsigned char *command, char *reply, int cmd_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ser_send_buf(upsfd, command, 6);
|
||||
ret = ser_send_buf(upsfd, command, cmd_len);
|
||||
if (ret < 0) {
|
||||
upsdebug_with_errno(2, "send");
|
||||
return -1;
|
||||
} else if (ret < 6) {
|
||||
} else if (ret < cmd_len) {
|
||||
upsdebug_hex(2, "send: truncated", command, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
upsdebug_hex(2, "send", command, ret);
|
||||
|
||||
ret = ser_get_buf(upsfd, reply, 8, 1, 0);
|
||||
ret = ser_get_buf_len(upsfd, reply, 8, 1, 0); /* it needs that this driver works with USB to Serial cable */
|
||||
if (ret < 0) {
|
||||
upsdebug_with_errno(2, "read");
|
||||
return -1;
|
||||
|
@ -95,49 +156,111 @@ void upsdrv_initinfo(void)
|
|||
{
|
||||
struct {
|
||||
const char *var;
|
||||
const int len;
|
||||
unsigned char len;
|
||||
} vartab[] = {
|
||||
{ "ups.model", 15 },
|
||||
{ "ups.firmware", 8 },
|
||||
{ "ups.serial", 10 },
|
||||
{ "ups.mfr.date", 4 },
|
||||
{ "ups.model",15 },
|
||||
{ "ups.firmware",8 },
|
||||
{ "ups.serial",10 },
|
||||
{ "ups.mfr.date",4 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
char buf[LARGEBUF];
|
||||
int i, index;
|
||||
int i,bitn,vari,ret=0,offset=4,readok=0;
|
||||
char command[6], reply[8];
|
||||
unsigned int value;
|
||||
|
||||
dstate_setinfo("ups.mfr", "%s", "Liebert");
|
||||
|
||||
for (i = 0; i < 37; i++) {
|
||||
char command[6], reply[8];
|
||||
int ret;
|
||||
for (vari = 0; vartab[vari].var; vari++) {
|
||||
upsdebugx(1, "reading: %s", vartab[vari].var);
|
||||
|
||||
snprintf(command, sizeof(command), "\x01\x88\x02\x01%c", i+4);
|
||||
for (i = 0; i < vartab[vari].len; i++) {
|
||||
snprintf(command, sizeof(command), "\x01\x88\x02\x01%c", i+offset);
|
||||
command[5] = cksum(command, 5);
|
||||
|
||||
ret = do_command((unsigned char *)command, reply);
|
||||
if (ret == 8) {
|
||||
ret = do_command((unsigned char *)command, reply, 6);
|
||||
if (ret < 8) {
|
||||
upsdebug_hex(2, "send: truncated", command, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
buf[i<<1] = reply[6];
|
||||
buf[(i<<1)+1] = reply[5];
|
||||
} else {
|
||||
buf[i<<1] = '\0';
|
||||
buf[(i<<1)+1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
buf[i<<1] = 0;
|
||||
upsdebugx(1, "return: %d (8=success)", ret);
|
||||
|
||||
if (strlen(buf) == 0) {
|
||||
if (ret == 8) { /* last command successful */
|
||||
dstate_setinfo(vartab[vari].var,"%s",buf);
|
||||
readok++;
|
||||
}
|
||||
offset+=vartab[vari].len;
|
||||
} /* for */
|
||||
if (!readok) {
|
||||
fatalx(EXIT_FAILURE, "ESP-II capable UPS not detected");
|
||||
}
|
||||
|
||||
for (index = 0, i = 0; vartab[i].var; index += vartab[i].len, i++) {
|
||||
char val[SMALLBUF];
|
||||
/* determine number of input & output phases and ups type */
|
||||
memcpy(command,cmd_upstype,6);
|
||||
ret = do_command((unsigned char *)command, reply, 6);
|
||||
if (ret < 8) {
|
||||
upsdebug_hex(2, "send: phase detection: truncated", command, ret);
|
||||
}
|
||||
else {
|
||||
/* input: from bit 0 to bit 1 (2 bits) */
|
||||
for (value=0,bitn=0;bitn<2;bitn++) {
|
||||
if (IsBitSet(reply[6],(unsigned short int)bitn)) /* bit range measurement on LSByte*/
|
||||
value+=(1<<(unsigned short int)(bitn - 0));
|
||||
}
|
||||
num_inphases=value;
|
||||
dstate_setinfo("input.phases", "%d", value);
|
||||
|
||||
snprintf(val, sizeof(val), "%.*s", vartab[i].len, &buf[index]);
|
||||
/* output: from bit 4 to bit 5 (2 bits)*/
|
||||
for (value=0,bitn=4;bitn<6;bitn++) {
|
||||
if (IsBitSet(reply[6],(unsigned short int)bitn)) /* bit range measurement on LSByte*/
|
||||
value+=(1<<(unsigned short int)(bitn - 4));
|
||||
}
|
||||
num_outphases=value;
|
||||
dstate_setinfo("output.phases", "%d", value);
|
||||
|
||||
dstate_setinfo(vartab[i].var, "%s", rtrim(val, ' '));
|
||||
if (reply[5] & (1<<4)) { /* ISOFFLINE */
|
||||
dstate_setinfo("ups.type", "offline") ;
|
||||
}
|
||||
else if (reply[5] & (1<<5)) { /* ISINTERACTIVE */
|
||||
dstate_setinfo("ups.type", "line-interactive") ;
|
||||
}
|
||||
else {
|
||||
dstate_setinfo("ups.type", "online") ;
|
||||
}
|
||||
}
|
||||
|
||||
/* determine scaling */
|
||||
/* full scaling output not defined yet, but we can differentiate sets of
|
||||
* multipliers based on a sample scaling reading */
|
||||
memcpy(command,cmd_scaling1,6);
|
||||
ret = do_command((unsigned char *)command, reply, 6);
|
||||
if (ret < 8) {
|
||||
upsdebug_hex(2, "send: scaling detection: truncated", command, ret);
|
||||
}
|
||||
else { /* add here multipliers that differentiate between models */
|
||||
switch (reply[6]) {
|
||||
case 1: /* GXT-2 */
|
||||
multi[M_FREQUENCY]=0.1;
|
||||
multi[M_VOLT_DC]=1.0;
|
||||
multi[M_POWER]=1.0;
|
||||
multi[M_NOMPOWER]=1.0;
|
||||
break;
|
||||
case 2: /* NXe */
|
||||
multi[M_FREQUENCY]=0.01;
|
||||
multi[M_VOLT_DC]=0.1;
|
||||
multi[M_POWER]=100.0;
|
||||
multi[M_NOMPOWER]=100.0;
|
||||
break;
|
||||
default: /* the default values from definition of multi will be used */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
upsh.instcmd = instcmd;
|
||||
|
@ -146,55 +269,145 @@ void upsdrv_initinfo(void)
|
|||
|
||||
void upsdrv_updateinfo(void)
|
||||
{
|
||||
struct {
|
||||
typedef struct {
|
||||
const unsigned char cmd[6];
|
||||
const char *var;
|
||||
const char *fmt;
|
||||
const double mult;
|
||||
} vartab[] = {
|
||||
{ { 1,149,2,1,4,157 }, "battery.charge", "%.0f", 1.0 },
|
||||
{ { 1,149,2,1,1,154 }, "battery.runtime", "%.0f", 60 },
|
||||
{ { 1,149,2,1,2,155 }, "battery.voltage", "%.1f", 0.1 },
|
||||
{ { 1,149,2,1,3,156 }, "battery.current", "%.2f", 0.01 },
|
||||
{ { 1,149,2,1,12,165 }, "battery.temperature", "%.1f", 0.1 },
|
||||
{ { 1,161,2,1,13,178 }, "battery.voltage.nominal", "%.1f", 0.1 },
|
||||
{ { 1,149,2,1,7,160 }, "ups.load", "%.0f", 1.0 },
|
||||
{ { 1,149,2,1,6,159 }, "ups.power", "%.0f", 1.0 },
|
||||
{ { 1,161,2,1,8,173 }, "ups.power.nominal", "%.0f", 1.0 },
|
||||
{ { 1,149,2,1,5,158 }, "ups.realpower", "%.0f", 1.0 },
|
||||
{ { 1,149,2,1,14,167 }, "ups.temperature", "%.1f", 0.1 },
|
||||
{ { 1,144,2,1,1,149 }, "input.voltage", "%.1f", 0.1 },
|
||||
{ { 1,149,2,1,8,161 }, "input.frequency", "%.1f", 0.1 },
|
||||
{ { 1,149,2,1,10,163 }, "input.frequency.nominal", "%.1f", 0.1 },
|
||||
{ { 1,144,2,1,5,153 }, "input.bypass.voltage", "%.1f", 0.1 },
|
||||
{ { 1,144,2,1,3,151 }, "output.voltage", "%.1f", 0.1 },
|
||||
{ { 1,149,2,1,9,162 }, "output.frequency", "%.1f", 0.1 },
|
||||
{ { 1,144,2,1,4,152 }, "output.current", "%.1f", 0.1 },
|
||||
const int multindex;
|
||||
} cmd_s;
|
||||
|
||||
static cmd_s vartab[] = { /* common vars */
|
||||
{ { 1,149,2,1,1,154 }, "battery.runtime", "%.0f", M_BAT_RUNTIME },
|
||||
{ { 1,149,2,1,2,155 }, "battery.voltage", "%.1f", M_VOLT_DC },
|
||||
{ { 1,149,2,1,3,156 }, "battery.current", "%.2f", M_CURRENT_DC },
|
||||
{ { 1,161,2,1,13,178 }, "battery.voltage.nominal", "%.1f", M_VOLT_DC },
|
||||
{ { 1,149,2,1,12,165 }, "battery.temperature", "%.1f", M_TEMPERATURE },
|
||||
{ { 1,149,2,1,14,167 }, "ups.temperature", "%.1f", M_TEMPERATURE },
|
||||
{ { 1,161,2,1,8,173 }, "ups.power.nominal", "%.0f", M_NOMPOWER },
|
||||
{ { 1,161,2,1,4,169 }, "ups.delay.start", "%.0f", M_10 },
|
||||
{ { 1,161,2,1,14,179 },"battery.runtime.low", "%.0f", M_BAT_RUNTIME },
|
||||
{ { 1,149,2,1,8,161 }, "input.frequency", "%.1f", M_FREQUENCY },
|
||||
{ { 1,149,2,1,10,163 }, "input.bypass.frequency", "%.1f", M_FREQUENCY },
|
||||
{ { 1,161,2,1,9,174 }, "input.frequency.nominal", "%.1f", M_FREQUENCY },
|
||||
{ { 1,149,2,1,9,162 }, "output.frequency", "%.1f", M_FREQUENCY },
|
||||
{ { 1,161,2,1,10,175 }, "output.frequency.nominal", "%.1f", M_FREQUENCY },
|
||||
{ { 0 }, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cmd_s vartab1o[] = { /* 1-phase out */
|
||||
{ { 1,149,2,1,7,160 }, "ups.load", "%.0f", M_LOADPERC },
|
||||
{ { 1,149,2,1,6,159 }, "ups.power", "%.0f", M_POWER },
|
||||
{ { 1,149,2,1,5,158 }, "ups.realpower", "%.0f", M_POWER },
|
||||
{ { 1,144,2,1,3,151 }, "output.voltage", "%.1f", M_VOLTAGE_O },
|
||||
{ { 1,144,2,1,4,152 }, "output.current", "%.1f", M_CURRENT_O },
|
||||
{ { 0 }, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cmd_s vartab1i[] = { /* 1-phase in*/
|
||||
{ { 1,144,2,1,1,149 }, "input.voltage", "%.1f", M_VOLTAGE_I },
|
||||
{ { 1,144,2,1,5,153 }, "input.bypass.voltage", "%.1f", M_VOLTAGE_B },
|
||||
{ { 1,144,2,1,6,154 }, "input.bypass.current", "%.1f", M_CURRENT_B },
|
||||
{ { 0 }, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cmd_s vartab3o[] = { /*3-phase out */
|
||||
{ { 1,144,2,1,24,172 }, "ups.L1.load", "%.0f", M_LOADPERC },
|
||||
{ { 1,145,2,1,24,173 }, "ups.L2.load", "%.0f", M_LOADPERC },
|
||||
{ { 1,146,2,1,24,174 }, "ups.L3.load", "%.0f", M_LOADPERC },
|
||||
{ { 1,144,2,1,22,170 }, "ups.L1.power", "%.0f", M_POWER },
|
||||
{ { 1,145,2,1,22,171 }, "ups.L2.power", "%.0f", M_POWER },
|
||||
{ { 1,146,2,1,22,172 }, "ups.L3.power", "%.0f", M_POWER },
|
||||
{ { 1,144,2,1,21,169 }, "ups.L1.realpower", "%.0f", M_POWER },
|
||||
{ { 1,145,2,1,21,170 }, "ups.L2.realpower", "%.0f", M_POWER },
|
||||
{ { 1,146,2,1,21,171 }, "ups.L3.realpower", "%.0f", M_POWER },
|
||||
{ { 1,144,2,1,3,151 }, "output.L1-N.voltage", "%.1f", M_VOLTAGE_O },
|
||||
{ { 1,145,2,1,3,152 }, "output.L2-N.voltage", "%.1f", M_VOLTAGE_O },
|
||||
{ { 1,146,2,1,3,153 }, "output.L3-N.voltage", "%.1f", M_VOLTAGE_O },
|
||||
{ { 1,144,2,1,14,162 }, "output.L1.crestfactor", "%.1f", M_0_1 },
|
||||
{ { 1,145,2,1,14,163 }, "output.L2.crestfactor", "%.1f", M_0_1 },
|
||||
{ { 1,146,2,1,14,164 }, "output.L3.crestfactor", "%.1f", M_0_1 },
|
||||
{ { 0 }, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cmd_s vartab3i[] = { /*3-phase in */
|
||||
{ { 1,144,2,1,1,149 }, "input.L1-N.voltage", "%.1f", M_VOLTAGE_I },
|
||||
{ { 1,145,2,1,1,150 }, "input.L2-N.voltage", "%.1f", M_VOLTAGE_I },
|
||||
{ { 1,146,2,1,1,151 }, "input.L3-N.voltage", "%.1f", M_VOLTAGE_I },
|
||||
|
||||
{ { 1,144,2,1,5,153 }, "input.L1-N.bypass.voltage", "%.1f", M_VOLTAGE_B },
|
||||
{ { 1,145,2,1,5,154 }, "input.L2-N.bypass.voltage", "%.1f", M_VOLTAGE_B },
|
||||
{ { 1,146,2,1,5,155 }, "input.L3-N.bypass.voltage", "%.1f", M_VOLTAGE_B },
|
||||
|
||||
{ { 1,144,2,1,6,154 }, "input.L1-N.bypass.current", "%.1f", M_CURRENT_B },
|
||||
{ { 1,145,2,1,6,155 }, "input.L2-N.bypass.current", "%.1f", M_CURRENT_B },
|
||||
{ { 1,146,2,1,6,156 }, "input.L3-N.bypass.current", "%.1f", M_CURRENT_B },
|
||||
|
||||
{ { 1,144,2,1,2,150 }, "input.L1.current", "%.1f", M_CURRENT_I },
|
||||
{ { 1,145,2,1,2,151 }, "input.L2.current", "%.1f", M_CURRENT_I },
|
||||
{ { 1,146,2,1,2,152 }, "input.L3.current", "%.1f", M_CURRENT_I },
|
||||
{ { 0 }, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static cmd_s * cmdin_p;
|
||||
static cmd_s * cmdout_p;
|
||||
|
||||
const char *val;
|
||||
char reply[8];
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; vartab[i].var; i++) {
|
||||
int16_t val;
|
||||
|
||||
ret = do_command(vartab[i].cmd, reply);
|
||||
ret = do_command(vartab[i].cmd, reply, 6);
|
||||
if (ret < 8) {
|
||||
continue;
|
||||
}
|
||||
|
||||
val = (unsigned char)reply[5];
|
||||
val <<= 8;
|
||||
val += (unsigned char)reply[6];
|
||||
dstate_setinfo(vartab[i].var, vartab[i].fmt, val * multi[vartab[i].multindex]);
|
||||
}
|
||||
|
||||
dstate_setinfo(vartab[i].var, vartab[i].fmt, val * vartab[i].mult);
|
||||
if (num_inphases>1){
|
||||
cmdin_p=vartab3i;
|
||||
}
|
||||
else {
|
||||
cmdin_p=vartab1i;
|
||||
}
|
||||
|
||||
if (num_outphases>1){
|
||||
cmdout_p=vartab3o;
|
||||
}
|
||||
else {
|
||||
cmdout_p=vartab1o;
|
||||
}
|
||||
|
||||
for (i = 0; cmdin_p[i].var; i++) {
|
||||
int16_t val;
|
||||
ret = do_command(cmdin_p[i].cmd, reply, 6);
|
||||
if (ret < 8) {
|
||||
continue;
|
||||
}
|
||||
val = (unsigned char)reply[5];
|
||||
val <<= 8;
|
||||
val += (unsigned char)reply[6];
|
||||
dstate_setinfo(cmdin_p[i].var, cmdin_p[i].fmt, val * multi[cmdin_p[i].multindex]);
|
||||
}
|
||||
|
||||
for (i = 0; cmdout_p[i].var; i++) {
|
||||
int16_t val;
|
||||
ret = do_command(cmdout_p[i].cmd, reply, 6);
|
||||
if (ret < 8) {
|
||||
continue;
|
||||
}
|
||||
val = (unsigned char)reply[5];
|
||||
val <<= 8;
|
||||
val += (unsigned char)reply[6];
|
||||
dstate_setinfo(cmdout_p[i].var, cmdout_p[i].fmt, val * multi[cmdout_p[i].multindex]);
|
||||
}
|
||||
|
||||
status_init();
|
||||
|
||||
ret = do_command(cmd_bitfield1, reply);
|
||||
ret = do_command(cmd_bitfield1, reply, 6);
|
||||
if (ret < 8) {
|
||||
upslogx(LOG_ERR, "Failed reading bitfield #1");
|
||||
dstate_datastale();
|
||||
|
@ -217,7 +430,7 @@ void upsdrv_updateinfo(void)
|
|||
}
|
||||
}
|
||||
|
||||
ret = do_command(cmd_bitfield2, reply);
|
||||
ret = do_command(cmd_bitfield2, reply, 6);
|
||||
if (ret < 8) {
|
||||
upslogx(LOG_ERR, "Failed reading bitfield #2");
|
||||
dstate_datastale();
|
||||
|
@ -240,7 +453,7 @@ void upsdrv_updateinfo(void)
|
|||
status_set("TRIM");
|
||||
}
|
||||
|
||||
ret = do_command(cmd_bitfield3, reply);
|
||||
ret = do_command(cmd_bitfield3, reply, 6);
|
||||
if (ret < 8) {
|
||||
upslogx(LOG_ERR, "Failed reading bitfield #3");
|
||||
dstate_datastale();
|
||||
|
@ -262,8 +475,13 @@ void upsdrv_updateinfo(void)
|
|||
|
||||
void upsdrv_shutdown(void)
|
||||
{
|
||||
/* replace with a proper shutdown function */
|
||||
fatalx(EXIT_FAILURE, "shutdown not supported");
|
||||
char reply[8];
|
||||
|
||||
if(!(do_command(cmd_setOutOffMode, reply, 8) != -1) &&
|
||||
(do_command(cmd_setOutOffDelay, reply, 8) != -1) &&
|
||||
(do_command(cmd_sysLoadKey, reply, 6) != -1) &&
|
||||
(do_command(cmd_shutdown, reply, 8) != -1))
|
||||
upslogx(LOG_ERR, "Failed to shutdown UPS");
|
||||
}
|
||||
|
||||
static int instcmd(const char *cmdname, const char *extra)
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
#define LIEBERT_HID_VERSION "Liebert HID 0.3"
|
||||
/* FIXME: experimental flag to be put in upsdrv_info */
|
||||
|
||||
/* Liebert */
|
||||
#define LIEBERT_VENDORID 0x06da
|
||||
/* Phoenixtec */
|
||||
#define LIEBERT_VENDORID 0x06da
|
||||
|
||||
/* USB IDs device table */
|
||||
static usb_device_id_t liebert_usb_device_table[] = {
|
||||
|
|
|
@ -258,6 +258,11 @@ static int main_arg(char *var, char *val)
|
|||
return 1; /* handled */
|
||||
}
|
||||
|
||||
if (!strcmp(var, "ignorelb")) {
|
||||
dstate_setinfo("driver.flag.ignorelb", "enabled");
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
/* any other flags are for the driver code */
|
||||
if (!val)
|
||||
return 0;
|
||||
|
@ -600,6 +605,28 @@ int main(int argc, char **argv)
|
|||
upsdrv_initinfo();
|
||||
upsdrv_updateinfo();
|
||||
|
||||
if (dstate_getinfo("driver.flag.ignorelb")) {
|
||||
int have_lb_method = 0;
|
||||
|
||||
if (dstate_getinfo("battery.charge") && dstate_getinfo("battery.charge.low")) {
|
||||
upslogx(LOG_INFO, "using 'battery.charge' to set battery low state");
|
||||
have_lb_method++;
|
||||
}
|
||||
|
||||
if (dstate_getinfo("battery.runtime") && dstate_getinfo("battery.runtime.low")) {
|
||||
upslogx(LOG_INFO, "using 'battery.runtime' to set battery low state");
|
||||
have_lb_method++;
|
||||
}
|
||||
|
||||
if (!have_lb_method) {
|
||||
fatalx(EXIT_FAILURE,
|
||||
"The 'ignorelb' flag is set, but there is no way to determine the\n"
|
||||
"battery state of charge.\n\n"
|
||||
"Only set this flag if both 'battery.charge' and 'battery.charge.low'\n"
|
||||
"and/or 'battery.runtime' and 'battery.runtime.low' are available.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* now we can start servicing requests */
|
||||
dstate_init(progname, upsname);
|
||||
|
||||
|
|
|
@ -62,12 +62,12 @@ static int instcmd(const char *cmdname, const char *extra);
|
|||
|
||||
/*
|
||||
Metasystem UPS data transfer are made with packet of the format:
|
||||
STX DATA_LENGHT DATA CHECKSUM
|
||||
STX DATA_LENGTH DATA CHECKSUM
|
||||
where:
|
||||
STX is 0x02 and is the start of transmission byte
|
||||
DATA_LENGHT is number of data bytes + the checksum byte
|
||||
DATA_LENGTH is number of data bytes + the checksum byte
|
||||
DATA ......
|
||||
CHECKSUM is the sum modulus 256 of all DATA bytes + DATA_LENGHT
|
||||
CHECKSUM is the sum modulus 256 of all DATA bytes + DATA_LENGTH
|
||||
|
||||
The answer from the UPS have the same packet format and the first
|
||||
data byte is equal to the command that the ups is answering to
|
||||
|
@ -114,7 +114,7 @@ void dump_buffer(unsigned char *buffer, int buf_len) {
|
|||
}
|
||||
|
||||
/* send a read command to the UPS, it retries 5 times before give up
|
||||
it's a 4 byte request (STX, LENGHT, COMMAND and CHECKSUM) */
|
||||
it's a 4 byte request (STX, LENGTH, COMMAND and CHECKSUM) */
|
||||
void send_read_command(char command) {
|
||||
int retry, sent;
|
||||
unsigned char buf[4];
|
||||
|
@ -122,9 +122,9 @@ void send_read_command(char command) {
|
|||
sent = 0;
|
||||
while ((sent != 4) && (retry < 5)) {
|
||||
buf[0]=0x02; /* STX Start of Transmission */
|
||||
buf[1]=0x02; /* data lenght(data + checksum byte) */
|
||||
buf[1]=0x02; /* data length(data + checksum byte) */
|
||||
buf[2]=command; /* command to send */
|
||||
buf[3]=buf[1] + buf[2]; /* checksum (sum modulus 256 of data bytes + lenght) */
|
||||
buf[3]=buf[1] + buf[2]; /* checksum (sum modulus 256 of data bytes + length) */
|
||||
if (retry == 4) send_zeros(); /* last retry is preceded by a serial reset...*/
|
||||
sent = ser_send_buf(upsfd, buf, 4);
|
||||
retry += 1;
|
||||
|
@ -134,29 +134,29 @@ void send_read_command(char command) {
|
|||
/* send a write command to the UPS, the write command and the value to be written are passed
|
||||
with a char* buffer
|
||||
it retries 5 times before give up */
|
||||
void send_write_command(unsigned char *command, int command_lenght) {
|
||||
void send_write_command(unsigned char *command, int command_length) {
|
||||
int i, retry, sent, checksum;
|
||||
unsigned char raw_buf[255];
|
||||
|
||||
/* prepares the raw data */
|
||||
raw_buf[0] = 0x02; /* STX byte */
|
||||
raw_buf[1] = (unsigned char)(command_lenght + 1); /* data lenght + checksum */
|
||||
memcpy(raw_buf+2, command, command_lenght);
|
||||
command_lenght += 2;
|
||||
raw_buf[1] = (unsigned char)(command_length + 1); /* data length + checksum */
|
||||
memcpy(raw_buf+2, command, command_length);
|
||||
command_length += 2;
|
||||
|
||||
/* calculate checksum */
|
||||
checksum = 0;
|
||||
for (i = 1; i < command_lenght; i++) checksum += raw_buf[i];
|
||||
for (i = 1; i < command_length; i++) checksum += raw_buf[i];
|
||||
checksum = checksum % 256;
|
||||
raw_buf[command_lenght] = (unsigned char)checksum;
|
||||
command_lenght +=1;
|
||||
raw_buf[command_length] = (unsigned char)checksum;
|
||||
command_length +=1;
|
||||
|
||||
retry = 0;
|
||||
sent = 0;
|
||||
while ((sent != (command_lenght)) && (retry < 5)) {
|
||||
while ((sent != (command_length)) && (retry < 5)) {
|
||||
if (retry == 4) send_zeros(); /* last retry is preceded by a serial reset... */
|
||||
sent = ser_send_buf(upsfd, raw_buf, (command_lenght));
|
||||
if (sent != (command_lenght)) printf("Error sending command %d\n", raw_buf[2]);
|
||||
sent = ser_send_buf(upsfd, raw_buf, (command_length));
|
||||
if (sent != (command_length)) printf("Error sending command %d\n", raw_buf[2]);
|
||||
retry += 1;
|
||||
}
|
||||
}
|
||||
|
@ -164,8 +164,8 @@ void send_write_command(unsigned char *command, int command_lenght) {
|
|||
|
||||
/* get the answer of a command from the ups */
|
||||
int get_answer(unsigned char *data) {
|
||||
unsigned char my_buf[255]; /* packet has a maximum lenght of 256 bytes */
|
||||
int packet_lenght, checksum, i, res;
|
||||
unsigned char my_buf[255]; /* packet has a maximum length of 256 bytes */
|
||||
int packet_length, checksum, i, res;
|
||||
/* Read STX byte */
|
||||
res = ser_get_char(upsfd, my_buf, 1, 0);
|
||||
if (res < 1) {
|
||||
|
@ -176,43 +176,43 @@ int get_answer(unsigned char *data) {
|
|||
ser_comm_fail("Receive error (STX): packet not on start!!\n");
|
||||
return -1;
|
||||
}
|
||||
/* Read data lenght byte */
|
||||
/* Read data length byte */
|
||||
res = ser_get_char(upsfd, my_buf, 1, 0);
|
||||
if (res < 1) {
|
||||
ser_comm_fail("Receive error (lenght): %d!!!\n", res);
|
||||
ser_comm_fail("Receive error (length): %d!!!\n", res);
|
||||
return -1;
|
||||
}
|
||||
packet_lenght = my_buf[0];
|
||||
if (packet_lenght < 2) {
|
||||
ser_comm_fail("Receive error (lenght): packet lenght %d!!!\n", packet_lenght);
|
||||
packet_length = my_buf[0];
|
||||
if (packet_length < 2) {
|
||||
ser_comm_fail("Receive error (length): packet length %d!!!\n", packet_length);
|
||||
return -1;
|
||||
}
|
||||
/* Try to read all the remainig bytes (packet_lenght) */
|
||||
res = ser_get_buf_len(upsfd, my_buf, packet_lenght, 1, 0);
|
||||
if (res != packet_lenght) {
|
||||
ser_comm_fail("Receive error (data): got %d bytes instead of %d!!!\n", res, packet_lenght);
|
||||
/* Try to read all the remainig bytes (packet_length) */
|
||||
res = ser_get_buf_len(upsfd, my_buf, packet_length, 1, 0);
|
||||
if (res != packet_length) {
|
||||
ser_comm_fail("Receive error (data): got %d bytes instead of %d!!!\n", res, packet_length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now we have the whole answer from the ups, we can checksum it
|
||||
checksum byte is equal to the sum modulus 256 of all the data bytes + packet_lenght
|
||||
checksum byte is equal to the sum modulus 256 of all the data bytes + packet_length
|
||||
(no STX no checksum byte itself) */
|
||||
checksum = packet_lenght;
|
||||
for (i = 0; i < (packet_lenght - 1); i++) checksum += my_buf[i];
|
||||
checksum = packet_length;
|
||||
for (i = 0; i < (packet_length - 1); i++) checksum += my_buf[i];
|
||||
checksum = checksum % 256;
|
||||
if (my_buf[packet_lenght-1] != checksum) {
|
||||
ser_comm_fail("checksum error! got %x instad of %x, received %d bytes \n", my_buf[packet_lenght - 1], checksum, packet_lenght);
|
||||
dump_buffer(my_buf, packet_lenght);
|
||||
if (my_buf[packet_length-1] != checksum) {
|
||||
ser_comm_fail("checksum error! got %x instad of %x, received %d bytes \n", my_buf[packet_length - 1], checksum, packet_length);
|
||||
dump_buffer(my_buf, packet_length);
|
||||
return -1;
|
||||
}
|
||||
packet_lenght-=1; /* get rid of the checksum byte */
|
||||
memcpy(data, my_buf, packet_lenght);
|
||||
return packet_lenght;
|
||||
packet_length-=1; /* get rid of the checksum byte */
|
||||
memcpy(data, my_buf, packet_length);
|
||||
return packet_length;
|
||||
}
|
||||
|
||||
/* send a read command and try get the answer, if something fails, it retries (5 times max)
|
||||
if it is on the 4th or 5th retry, it will flush the serial before sending commands
|
||||
it returns the lenght of the received answer or -1 in case of failure */
|
||||
it returns the length of the received answer or -1 in case of failure */
|
||||
int command_read_sequence(unsigned char command, unsigned char *data) {
|
||||
int bytes_read = 0;
|
||||
int retry = 0;
|
||||
|
@ -234,13 +234,13 @@ int command_read_sequence(unsigned char command, unsigned char *data) {
|
|||
|
||||
/* send a write command and try get the answer, if something fails, it retries (5 times max)
|
||||
if it is on the 4th or 5th retry, it will flush the serial before sending commands
|
||||
it returns the lenght of the received answer or -1 in case of failure */
|
||||
int command_write_sequence(unsigned char *command, int command_lenght, unsigned char *answer) {
|
||||
it returns the length of the received answer or -1 in case of failure */
|
||||
int command_write_sequence(unsigned char *command, int command_length, unsigned char *answer) {
|
||||
int bytes_read = 0;
|
||||
int retry = 0;
|
||||
|
||||
while ((bytes_read < 1) && (retry < 5)) {
|
||||
send_write_command(command, command_lenght);
|
||||
send_write_command(command, command_length);
|
||||
bytes_read = get_answer(answer);
|
||||
if (retry > 2) ser_flush_in(upsfd, "", 0);
|
||||
retry += 1;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "usbhid-ups.h"
|
||||
#include "mge-hid.h"
|
||||
|
||||
#define MGE_HID_VERSION "MGE HID 1.19"
|
||||
#define MGE_HID_VERSION "MGE HID 1.21"
|
||||
|
||||
/* (prev. MGE Office Protection Systems, prev. MGE UPS SYSTEMS) */
|
||||
/* Eaton */
|
||||
|
@ -35,6 +35,9 @@
|
|||
/* Dell */
|
||||
#define DELL_VENDORID 0x047c
|
||||
|
||||
/* Powerware */
|
||||
#define POWERWARE_VENDORID 0x0592
|
||||
|
||||
#ifndef SHUT_MODE
|
||||
#include "usb-common.h"
|
||||
|
||||
|
@ -47,6 +50,9 @@ static usb_device_id_t mge_usb_device_table[] = {
|
|||
/* various models */
|
||||
{ USB_DEVICE(DELL_VENDORID, 0xffff), NULL },
|
||||
|
||||
/* PW 9140 */
|
||||
{ USB_DEVICE(POWERWARE_VENDORID, 0x0004), NULL },
|
||||
|
||||
/* Terminating entry */
|
||||
{ -1, -1, NULL }
|
||||
};
|
||||
|
@ -492,7 +498,8 @@ static usage_lkp_t mge_usage_lkp[] = {
|
|||
{ "HighHumidity", 0xffff0082 },
|
||||
{ "LowTemperature", 0xffff0083 },
|
||||
{ "HighTemperature", 0xffff0084 },
|
||||
/* 0xffff0085-0xffff008f => Reserved */
|
||||
/* 0xffff0085-0xffff008f (minus 0xffff0086) => Reserved */
|
||||
{ "Efficiency", 0xffff0086 },
|
||||
{ "Count", 0xffff0090 },
|
||||
{ "Timer", 0xffff0091 },
|
||||
{ "Interval", 0xffff0092 },
|
||||
|
@ -582,11 +589,17 @@ static models_name_t mge_model_names [] =
|
|||
{ "PROTECTIONCENTER", "500", MGE_DEFAULT, "Protection Center 500" },
|
||||
{ "PROTECTIONCENTER", "675", MGE_DEFAULT, "Protection Center 675" },
|
||||
|
||||
/* Protection Station */
|
||||
/* Protection Station, supports Eco control */
|
||||
{ "Protection Station", "500", MGE_PEGASUS, NULL },
|
||||
{ "Protection Station", "650", MGE_PEGASUS, NULL },
|
||||
{ "Protection Station", "800", MGE_PEGASUS, NULL },
|
||||
|
||||
/* Ellipse ECO, also supports Eco control */
|
||||
{ "Ellipse ECO", "650", MGE_PEGASUS, NULL },
|
||||
{ "Ellipse ECO", "800", MGE_PEGASUS, NULL },
|
||||
{ "Ellipse ECO", "1200", MGE_PEGASUS, NULL },
|
||||
{ "Ellipse ECO", "1600", MGE_PEGASUS, NULL },
|
||||
|
||||
/* Evolution models */
|
||||
{ "Evolution", "500", MGE_DEFAULT, "Pulsar Evolution 500" },
|
||||
{ "Evolution", "800", MGE_DEFAULT, "Pulsar Evolution 800" },
|
||||
|
@ -689,6 +702,7 @@ static hid_info_t mge_hid2nut[] =
|
|||
{ "battery.charge.restart", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.PowerSummary.RestartLevel", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "battery.capacity", 0, 0, "UPS.BatterySystem.Battery.DesignCapacity", NULL, "%s", HU_FLAG_STATIC, mge_battery_capacity }, /* conversion needed from As to Ah */
|
||||
{ "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.runtime.elapsed", 0, 0, "UPS.StatisticSystem.Input.[1].Statistic.[1].Time", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL },
|
||||
{ "battery.temperature", 0, 0, "UPS.BatterySystem.Battery.Temperature", NULL, "%s", 0, kelvin_celsius_conversion },
|
||||
{ "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion },
|
||||
|
@ -700,6 +714,7 @@ static hid_info_t mge_hid2nut[] =
|
|||
{ "battery.energysave", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Input.[3].EnergySaving", NULL, "%s", HU_FLAG_SEMI_STATIC, yes_no_info },
|
||||
|
||||
/* UPS page */
|
||||
{ "ups.efficiency", 0, 0, "UPS.PowerConverter.Output.Efficiency", NULL, "%.0f", 0, NULL },
|
||||
{ "ups.firmware", 0, 0, "UPS.PowerSummary.iVersion", NULL, "%s", HU_FLAG_STATIC, stringid_conversion },
|
||||
{ "ups.load", 0, 0, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", 0, NULL },
|
||||
{ "ups.load.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.Flow.[4].ConfigPercentLoad", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
|
@ -767,7 +782,7 @@ static hid_info_t mge_hid2nut[] =
|
|||
/* Battery DC voltage too high! */
|
||||
{ "BOOL", 0, 0, "UPS.BatterySystem.Battery.PresentStatus.VoltageTooHigh", NULL, NULL, 0, battvolthi_info },
|
||||
{ "BOOL", 0, 0, "UPS.BatterySystem.Charger.PresentStatus.VoltageTooLow", NULL, NULL, 0, battvoltlo_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.VoltageTooLow", NULL, NULL, 0, battvoltlo_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.VoltageTooLow", NULL, NULL, 0, mge_onbatt_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.InternalFailure", NULL, NULL, 0, commfault_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.OverTemperature", NULL, NULL, 0, overheat_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, NULL, 0, shutdownimm_info },
|
||||
|
|
|
@ -221,13 +221,13 @@ unsigned char * CmdSerial(unsigned char *OutBuffer, int Len, unsigned char *RetB
|
|||
unsigned char *p ;
|
||||
int BuffLen ;
|
||||
|
||||
// The default error code (no received character)
|
||||
/* The default error code (no received character) */
|
||||
ErrCode = ERR_COM_NO_CHARS ;
|
||||
|
||||
SendCmdToSerial(OutBuffer, Len) ;
|
||||
usleep(10000) ; // small delay (1/100 s))
|
||||
usleep(10000) ; /* small delay (1/100 s) */
|
||||
|
||||
// get chars until timeout
|
||||
/* get chars until timeout */
|
||||
BuffLen = 0 ;
|
||||
while (ser_get_char(upsfd, TmpBuff, 0, 10000) == 1)
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* This model is based on PowerCom (www.powercom.com) models.
|
||||
* -Socomec Sicon Egys 420
|
||||
*
|
||||
* $Id: powercom.c 2336 2010-02-11 20:16:43Z adkorte-guest $
|
||||
* $Id: powercom.c 2990 2011-05-19 18:34:09Z aquette $
|
||||
*
|
||||
* Copyrights:
|
||||
* (C) 2002 Simon Rozman <simon@rozman.net>
|
||||
|
@ -51,6 +51,15 @@
|
|||
* - strange battery level on BNT1200AP in online mode( & may be on other models)
|
||||
* - i don't know how connect to IMP|IMD USB
|
||||
* - i havn't specs for BNT 100-120V models. Add BNT-other type for it
|
||||
*
|
||||
* rev 0.13: Keven Ates <atescomp@gmail.com>
|
||||
* - Modified functions to work for BNT-other 100-120V models.
|
||||
* - Modified BNT-other type defaults to work for the BNT 1500A 120VA model.
|
||||
* - Documented the type[] values purpose in a condensed format.
|
||||
* - BNT-other can be used to perform a complete user override of values for all PowerCom models, detected or not.
|
||||
*
|
||||
* Tested on: BNT-1500A
|
||||
*
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
@ -59,7 +68,7 @@
|
|||
#include "math.h"
|
||||
|
||||
#define DRIVER_NAME "PowerCom protocol UPS driver"
|
||||
#define DRIVER_VERSION "0.12"
|
||||
#define DRIVER_VERSION "0.13"
|
||||
|
||||
/* driver description structure */
|
||||
upsdrv_info_t upsdrv_info = {
|
||||
|
@ -92,7 +101,28 @@ static unsigned int type = 0;
|
|||
static void dtr0rts1 (void);
|
||||
static void no_flow_control (void);
|
||||
|
||||
/* struct defining types */
|
||||
/* struct defining types
|
||||
* ---------------------
|
||||
* See powercom.h for detailed information and functions.
|
||||
*
|
||||
* The following type defaults use this definition:
|
||||
*
|
||||
* "TypeID",
|
||||
* ByteCount,
|
||||
* { "FlowControlString", FlowControlFuncPtr },
|
||||
* { { ValidationIndex, ValidationValue },
|
||||
* { ValidationIndex, ValidationValue },
|
||||
* { ValidationIndex, ValidationValue } },
|
||||
* { { DelayShutdownMinutes, DelayShutdownSeconds },
|
||||
* UseMinutesChar'y''n' },
|
||||
* { FrequencyFactor, FrequencyConstant },
|
||||
* { OfflineLoadFactor, OfflineLoadConstant,
|
||||
* OnlineLoadFactor, OnlineLoadConstant },
|
||||
* { OfflineBatteryFactor, OfflineLoad%Factor, OfflineBatteryConstant,
|
||||
* OnlineBatteryFactor, OnlineBatteryConstant },
|
||||
* { 240VoltageFactor, 240VoltageConstant,
|
||||
* 120VoltageFactor, 120VoltageConstant },
|
||||
*/
|
||||
static struct type types[] = {
|
||||
{
|
||||
"Trust",
|
||||
|
@ -166,10 +196,10 @@ static struct type types[] = {
|
|||
{ "no_flow_control", no_flow_control },
|
||||
{ { 8U, 0U }, { 8U, 0U }, { 8U, 0U } },
|
||||
{ { 1U, 30U }, 'y' },
|
||||
{ 0.00020803, 0.0 },
|
||||
{ 1.4474, 0.0, 0.8594, 0.0 },
|
||||
{ 5.0000, 0.3268, -825.00, 0.46511, 0 },
|
||||
{ 1.9216, -0.0977, 0.82857, 0.0000 },
|
||||
{ 0.00027778, 0.0000 },
|
||||
{ 1.0000, 0.0000, 1.0000, 0.0000 },
|
||||
{ 1.0000, 0.0000, 0.0000, 1.0000, 0.0000 },
|
||||
{ 2.0000, 0.0000, 2.0000, 0.0000 },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -217,10 +247,10 @@ enum status {
|
|||
OFF = 128U
|
||||
};
|
||||
|
||||
unsigned int voltages[]={100,110,115,120,0,0,0,200,220,230,240};
|
||||
unsigned int BNTmodels[]={0,400,500,600,800,801,1000,1200,1500,2000};
|
||||
unsigned int KINmodels[]={0,425,500,525,625,800,1000,1200,1500,1600,2200,2200,2500,3000,5000};
|
||||
unsigned int IMPmodels[]={0,425,525,625,825,1025,1200,1500,2000};
|
||||
unsigned int voltages[]={100,110,115,120,0,0,0,200,220,230,240,0,0,0,0,0};
|
||||
unsigned int BNTmodels[]={0,400,500,600,800,801,1000,1200,1500,2000,0,0,0,0,0,0};
|
||||
unsigned int KINmodels[]={0,425,500,525,625,800,1000,1200,1500,1600,2200,2200,2500,3000,5000,0};
|
||||
unsigned int IMPmodels[]={0,425,525,625,825,1025,1200,1500,2000,0,0,0,0,0,0,0};
|
||||
|
||||
/*
|
||||
* local used functions
|
||||
|
@ -338,6 +368,7 @@ static int ups_getinfo(void)
|
|||
|
||||
/* optional dump of raw data */
|
||||
if (nut_debug_level > 4) {
|
||||
/* FIXME: use upsdebug_hex() ? */
|
||||
printf("Raw data from UPS:\n");
|
||||
for (i = 0; i < types[type].num_of_bytes_from_ups; i++) {
|
||||
printf("%2d 0x%02x (%c)\n", i, raw_data[i], raw_data[i]>=0x20 ? raw_data[i] : ' ');
|
||||
|
@ -475,7 +506,7 @@ static float output_voltage(void)
|
|||
|
||||
static float input_freq(void)
|
||||
{
|
||||
if ( !strncmp(types[type].name, "BNT",3) || !strcmp(types[type].name, "KIN"))
|
||||
if ( !strcmp(types[type].name, "BNT") || !strcmp(types[type].name, "KIN"))
|
||||
return 4807.0/raw_data[INPUT_FREQUENCY];
|
||||
else if ( !strcmp(types[type].name, "IMP"))
|
||||
return raw_data[INPUT_FREQUENCY];
|
||||
|
@ -487,7 +518,7 @@ static float input_freq(void)
|
|||
|
||||
static float output_freq(void)
|
||||
{
|
||||
if ( !strncmp(types[type].name, "BNT",3) || !strcmp(types[type].name, "KIN"))
|
||||
if ( !strcmp(types[type].name, "BNT") || !strcmp(types[type].name, "KIN"))
|
||||
return 4807.0/raw_data[OUTPUT_FREQUENCY];
|
||||
else if ( !strcmp(types[type].name, "IMP"))
|
||||
return raw_data[OUTPUT_FREQUENCY];
|
||||
|
@ -574,7 +605,7 @@ static float batt_level(void)
|
|||
int bat0,bat29,bat100,model;
|
||||
float battval;
|
||||
|
||||
if ( !strncmp(types[type].name, "BNT",3) ) {
|
||||
if ( !strcmp(types[type].name, "BNT") ) {
|
||||
bat0=157;
|
||||
bat29=165;
|
||||
bat100=193;
|
||||
|
@ -617,11 +648,13 @@ static float batt_level(void)
|
|||
}
|
||||
if ( !strcmp(types[type].name, "IMP"))
|
||||
return raw_data[BATTERY_CHARGE];
|
||||
return raw_data[STATUS_A] & ONLINE ?
|
||||
return raw_data[STATUS_A] & ONLINE ? /* Are we on battery power? */
|
||||
/* Yes */
|
||||
types[type].battpct[0] * raw_data[BATTERY_CHARGE] +
|
||||
types[type].battpct[1] * load_level() + types[type].battpct[2] :
|
||||
/* No */
|
||||
types[type].battpct[3] * raw_data[BATTERY_CHARGE] +
|
||||
types[type].battpct[4];
|
||||
types[type].battpct[4];
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -852,27 +885,31 @@ void upsdrv_initups(void)
|
|||
|
||||
/* setup flow control */
|
||||
types[type].flowControl.setup_flow_control();
|
||||
|
||||
/* Setup Model and LineVoltage */
|
||||
if (!strncmp(types[type].name, "BNT",3) || !strcmp(types[type].name, "KIN") || !strcmp(types[type].name, "IMP")){
|
||||
if (!ups_getinfo()) return;
|
||||
if (raw_data[UPSVERSION]==0xFF){
|
||||
/* Give "BNT-other" a chance! */
|
||||
if (raw_data[MODELNAME]==0x42 || raw_data[MODELNAME]==0x4B){
|
||||
model=BNTmodels[raw_data[MODELNUMBER]/16];
|
||||
if (!strcmp(types[type].name, "BNT-other"))
|
||||
types[type].name="BNT-other";
|
||||
else if (raw_data[MODELNAME]==0x42)
|
||||
types[type].name="BNT";
|
||||
else if (raw_data[MODELNAME]==0x4B){
|
||||
types[type].name="KIN";
|
||||
model=KINmodels[raw_data[MODELNUMBER]/16];
|
||||
}
|
||||
}
|
||||
else if (raw_data[UPSVERSION]==0xFF){
|
||||
types[type].name="IMP";
|
||||
model=IMPmodels[raw_data[MODELNUMBER]/16];
|
||||
}
|
||||
if (raw_data[MODELNAME]==0x42){
|
||||
if (!strcmp(types[type].name, "BNT-other"))
|
||||
types[type].name="BNT-other";
|
||||
else
|
||||
types[type].name="BNT";
|
||||
model=BNTmodels[raw_data[MODELNUMBER]/16];
|
||||
}
|
||||
if (raw_data[MODELNAME]==0x4B){
|
||||
types[type].name="KIN";
|
||||
model=KINmodels[raw_data[MODELNUMBER]/16];
|
||||
}
|
||||
linevoltage=voltages[raw_data[MODELNUMBER]%16];
|
||||
snprintf(buf,sizeof(buf),"%s-%dAP",types[type].name,model);
|
||||
modelname=buf;
|
||||
upsdebugx(1,"Detected: %s , %dV",modelname,linevoltage);
|
||||
if (!strcmp(modelname, "Unknown"))
|
||||
modelname=buf;
|
||||
upsdebugx(1,"Detected: %s , %dV",buf,linevoltage);
|
||||
if (ser_send_char (upsfd, BATTERY_TEST) != 1) {
|
||||
upslogx(LOG_NOTICE, "writing error");
|
||||
dstate_datastale();
|
||||
|
@ -922,23 +959,65 @@ void upsdrv_initups(void)
|
|||
/* display help */
|
||||
void upsdrv_help(void)
|
||||
{
|
||||
printf("You must specify type in ups.conf\n");
|
||||
printf("Type of UPS like 'Trust', 'Egys', 'KP625AP', 'IMP', 'KIN' or 'BNT' or 'BNT-other' (default: 'Trust')\n");
|
||||
printf("BNT-other - it's a special type for BNT 100-120V models \n");
|
||||
printf("You can additional cpecify next variables:\n");
|
||||
printf(" shutdownArguments: The number of delay arguments and their values for the shutdown operation\n");
|
||||
printf("Also, you can specify next variables (not work for 'IMP', 'KIN' or 'BNT', because detected automatically or known\n");
|
||||
printf(" manufacturer: Specify manufacturer name (default: 'PowerCom')\n");
|
||||
printf(" modelname: Specify model name, because it cannot detect automagically (default: Unknown)\n");
|
||||
printf(" serialnumber: Specify serial number, because it cannot detect automatically (default: Unknown)\n");
|
||||
printf(" linevoltage: Specify line voltage (110-120 or 220-240 V), if it cannot detect automatically (default: 230 V)\n");
|
||||
printf(" numOfBytesFromUPS: The number of bytes in a UPS frame\n");
|
||||
printf(" methodOfFlowControl: The flow control method engaged by the UPS\n");
|
||||
printf(" validationSequence: 3 pairs to be used for validating the UPS\n");
|
||||
printf(" voltage: A quad to convert the raw data to human readable voltage\n");
|
||||
printf(" frequency: A pair to convert the raw data to human readable freqency\n");
|
||||
printf(" batteryPercentage: A 5 tuple to convert the raw data to human readable battery percentage\n");
|
||||
printf(" loadPercentage: A quad to convert the raw data to human readable load percentage\n");
|
||||
// 1 2 3 4 5 6 7 8
|
||||
// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 MAX
|
||||
printf("\n");
|
||||
printf("Specify UPS information in the ups.conf file.\n");
|
||||
printf(" type: Type of UPS: 'Trust','Egys','KP625AP','IMP','KIN','BNT',\n");
|
||||
printf(" 'BNT-other' (default: 'Trust')\n");
|
||||
printf(" 'BNT-other' is a special type intended for BNT 100-120V models,\n");
|
||||
printf(" but can be used to override ALL models.\n");
|
||||
printf("You can additional specify these variables:\n");
|
||||
printf(" manufacturer: Manufacturer name (default: 'PowerCom')\n");
|
||||
printf(" modelname: Model name (default: 'Unknown' or autodetected)\n");
|
||||
printf(" serialnumber: Serial number (default: Unknown)\n");
|
||||
printf(" shutdownArguments: 3 delay arguments for the shutdown operation:\n");
|
||||
printf(" {{Minutes,Seconds},UseMinutes?}\n");
|
||||
printf(" where Minutes and Seconds are integer, UseMinutes? is either\n");
|
||||
printf(" 'y' or 'n'.\n");
|
||||
printf("You can specify these variables if not automagically detected for types\n");
|
||||
printf(" 'IMP','KIN','BNT'\n");
|
||||
printf(" linevoltage: Line voltage: 110-120 or 220-240 (default: 230)\n");
|
||||
printf(" numOfBytesFromUPS: Number of bytes in a UPS frame: 16 is common, 11 for 'Trust'\n");
|
||||
printf(" methodOfFlowControl: Flow control method for UPS:\n");
|
||||
printf(" 'dtr0rts1', 'dtr1' or 'no_flow_control'\n");
|
||||
printf(" validationSequence: 3 pairs of validation values: {{I,V},{I,V},{I,V}}\n");
|
||||
printf(" where I is the index into BytesFromUPS (see numOfBytesFromUPS)\n");
|
||||
printf(" and V is the value for the ByteIndex to match.\n");
|
||||
printf(" frequency: Input & Output Frequency conversion values: {A, B}\n");
|
||||
printf(" used in function: 1/(A*x+B)\n");
|
||||
printf(" If the raw value x IS the frequency, then A=1/(x^2), B=0\n");
|
||||
printf(" loadPercentage: Load conversion values for Battery and Line load: {BA,BB,LA,LB}\n");
|
||||
printf(" used in function: A*x+B\n");
|
||||
printf(" If the raw value x IS the Load Percent, then A=1, B=0\n");
|
||||
printf(" batteryPercentage: Battery conversion values for Battery and Line power:\n");
|
||||
printf(" {A,B,C,D,E}\n");
|
||||
printf(" used in functions: (Battery) A*x+B*y+C, (Line) D*x+E\n");
|
||||
printf(" If the raw value x IS the Battery Percent, then\n");
|
||||
printf(" A=1, B=0, C=0, D=1, E=0\n");
|
||||
printf(" voltage: Voltage conversion values for 240 and 120 voltage:\n");
|
||||
printf(" {240A,240B,120A,120B}\n");
|
||||
printf(" used in function: A*x+B\n");
|
||||
printf(" If the raw value x IS HALF the Voltage, then A=2, B=0\n\n");
|
||||
|
||||
printf("Example for BNT1500AP in ups.conf:\n");
|
||||
printf("[BNT1500AP]\n");
|
||||
printf(" driver = powercom\n");
|
||||
printf(" port = /dev/ttyS0\n");
|
||||
printf(" desc = \"PowerCom BNT 1500 AP\"\n");
|
||||
printf(" manufacturer = PowerCom\n");
|
||||
printf(" modelname = BNT1500AP\n");
|
||||
printf(" serialnumber = 13245678900\n");
|
||||
printf(" type = BNT-other\n");
|
||||
printf("# linevoltage = 120\n");
|
||||
printf("# numOfBytesFromUPS = 16\n");
|
||||
printf("# methodOfFlowControl = no_flow_control\n");
|
||||
printf("# validationSequence = {{8,0},{8,0},{8,0}}\n");
|
||||
printf("# shutdownArguments = {{1,30},y}\n");
|
||||
printf("# frequency = {0.00027778,0.0000}\n");
|
||||
printf("# loadPercentage = {1.0000,0.0,1.0000,0.0}\n");
|
||||
printf("# batteryPercentage = {1.0000,0.0000,0.0000,1.0000,0.0000}\n");
|
||||
printf("# voltage = {2.0000,0.0000,2.0000,0.0000}\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -962,20 +1041,36 @@ void upsdrv_initinfo(void)
|
|||
/* define possible arguments */
|
||||
void upsdrv_makevartable(void)
|
||||
{
|
||||
addvar(VAR_VALUE, "manufacturer", "Specify manufacturer name (default: 'PowerCom')");
|
||||
addvar(VAR_VALUE, "linevoltage", "Specify line voltage (110-120 or 220-240 V), if it cannot detect automatically (default: 230 V)");
|
||||
addvar(VAR_VALUE, "modelname", "Specify model name, because it cannot detect automagically (default: Unknown)");
|
||||
addvar(VAR_VALUE, "serialnumber", "Specify serial number, because it cannot detect automatically (default: Unknown)");
|
||||
addvar(VAR_VALUE, "type", "Type of UPS like 'Trust', 'Egys', 'KP625AP', 'IMP', 'KIN' or 'BNT' or 'BNT-other' (default: 'Trust')");
|
||||
addvar(VAR_VALUE, "numOfBytesFromUPS", "The number of bytes in a UPS frame");
|
||||
addvar(VAR_VALUE, "methodOfFlowControl", "The flow control method engaged by the UPS");
|
||||
addvar(VAR_VALUE, "shutdownArguments", "The number of delay arguments and their values for the shutdown operation");
|
||||
addvar(VAR_VALUE, "validationSequence", "3 pairs to be used for validating the UPS");
|
||||
// 1 2 3 4 5 6 7 8
|
||||
//2345678901234567890123456789012345678901234567890123456789012345678901234567890 MAX
|
||||
addvar(VAR_VALUE, "type",
|
||||
"Type of UPS: 'Trust','Egys','KP625AP','IMP','KIN','BNT','BNT-other'\n"
|
||||
" (default: 'Trust')");
|
||||
addvar(VAR_VALUE, "manufacturer",
|
||||
"Manufacturer name (default: 'PowerCom')");
|
||||
addvar(VAR_VALUE, "modelname",
|
||||
"Model name [cannot be detected] (default: Unknown)");
|
||||
addvar(VAR_VALUE, "serialnumber",
|
||||
"Serial number [cannot be detected] (default: Unknown)");
|
||||
addvar(VAR_VALUE, "shutdownArguments",
|
||||
"Delay values for shutdown: Minutes, Seconds, UseMinutes?'y'or'n'");
|
||||
addvar(VAR_VALUE, "linevoltage",
|
||||
"Line voltage 110-120 or 220-240 V (default: 230)");
|
||||
addvar(VAR_VALUE, "numOfBytesFromUPS",
|
||||
"The number of bytes in a UPS frame");
|
||||
addvar(VAR_VALUE, "methodOfFlowControl",
|
||||
"Flow control method for UPS: 'dtr0rts1' or 'no_flow_control'");
|
||||
addvar(VAR_VALUE, "validationSequence",
|
||||
"Validation values: ByteIndex, ByteValue x 3");
|
||||
if ( strcmp(types[type].name, "KIN") && strcmp(types[type].name, "BNT") && strcmp(types[type].name, "IMP")) {
|
||||
addvar(VAR_VALUE, "voltage", "A quad to convert the raw data to human readable voltage");
|
||||
addvar(VAR_VALUE, "frequency", "A pair to convert the raw data to human readable freqency");
|
||||
addvar(VAR_VALUE, "batteryPercentage", "A 5 tuple to convert the raw data to human readable battery percentage");
|
||||
addvar(VAR_VALUE, "loadPercentage", "A quad to convert the raw data to human readable load percentage");
|
||||
addvar(VAR_VALUE, "frequency",
|
||||
"Frequency conversion values: FreqFactor, FreqConst");
|
||||
addvar(VAR_VALUE, "loadPercentage",
|
||||
"Load conversion values: OffFactor, OffConst, OnFactor, OnConst");
|
||||
addvar(VAR_VALUE, "batteryPercentage",
|
||||
"Battery conversion values: OffFactor, LoadFactor, OffConst, OnFactor, OnConst");
|
||||
addvar(VAR_VALUE, "voltage",
|
||||
"Voltage conversion values: 240VFactor, 240VConst, 120VFactor, 120VConst");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* powercom.h - defines for the newpowercom.c driver
|
||||
*
|
||||
* $Id: powercom.h 2627 2010-10-26 21:09:34Z adkorte-guest $
|
||||
* $Id: powercom.h 2984 2011-05-13 13:18:34Z aquette $
|
||||
*
|
||||
* Copyrights:
|
||||
* (C) 2002 Simon Rozman <simon@rozman.net>
|
||||
|
@ -62,39 +62,39 @@ struct type {
|
|||
* the COUNTER commands while others are known to work with the
|
||||
* seconds argument alone.
|
||||
*/
|
||||
struct deley_for_power_kill {
|
||||
struct delay_for_power_kill {
|
||||
unsigned int delay[2]; /* { minutes, seconds } */
|
||||
unsigned char minutesShouldBeUsed;
|
||||
/* 'n' in case the minutes value, which is deley[0], should
|
||||
/* 'n' in case the minutes value, which is delay[0], should
|
||||
* be skipped and not sent to the UPS.
|
||||
*/
|
||||
} shutdown_arguments;
|
||||
|
||||
/* parameters to calculate input and output freq., one pair for
|
||||
* each type:
|
||||
* Each pair defines parameters for 1/(A*x+B) to calculate freq.
|
||||
* from raw data
|
||||
/* parameters to calculate input and output freq., one pair used for
|
||||
* both input and output functions:
|
||||
* The pair [0],[1] defines parameters for 1/(A*x+B) to calculate freq.
|
||||
* from raw data 'x'.
|
||||
*/
|
||||
float freq[2];
|
||||
|
||||
/* parameters to calculate load %, two pairs for each type:
|
||||
* First pair defines the parameters for A*x+B to calculate load
|
||||
* from raw data when offline and the second pair is used when
|
||||
* First pair [0],[1] defines the parameters for A*x+B to calculate load
|
||||
* from raw data when offline and the second pair [2],[3] is used when
|
||||
* online
|
||||
*/
|
||||
float loadpct[4];
|
||||
|
||||
/* parameters to calculate battery %, five parameters for each type:
|
||||
* First three params defines the parameters for A*x+B*y+C to calculate
|
||||
* First three params [0],[1],[2] defines the parameters for A*x+B*y+C to calculate
|
||||
* battery % (x is raw data, y is load %) when offline.
|
||||
* Fourth and fifth parameters are used to calculate D*y+E when online.
|
||||
* Fourth and fifth parameters [3],[4] are used to calculate D*x+E when online.
|
||||
*/
|
||||
float battpct[5];
|
||||
|
||||
/* parameters to calculate utility and output voltage, two pairs for
|
||||
* each type:
|
||||
* First pair defines the parameters for A*x+B to calculate utility
|
||||
* from raw data when line voltage is >=220 and the second pair
|
||||
* First pair [0],[1] defines the parameters for A*x+B to calculate utility
|
||||
* from raw data when line voltage is >=220 and the second pair [2],[3]
|
||||
* is used otherwise.
|
||||
*/
|
||||
float voltage[4];
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
2005/10/26 - Version 0.40 - Operational-2 release
|
||||
2005/11/29 - Version 0.50 - rhino commands release
|
||||
|
||||
|
||||
|
||||
http://www.microsol.com.br
|
||||
|
||||
*/
|
||||
|
@ -63,28 +63,27 @@ typedef int bool_t;
|
|||
#define CMD_PASSOFF 0x0006
|
||||
#define CMD_UPSCONT 0x0053
|
||||
|
||||
/* xoff - xon protocol
|
||||
#define _SOH = 0x01; // start of header
|
||||
#define _EOT = 0x04; // end of transmission
|
||||
#define _ACK = 0x06; // acknoledge (positive)
|
||||
#define _DLE = 0x10; // data link escape
|
||||
#define _XOn = 0x11; // transmit on
|
||||
#define _XOff = 0x13; // transmit off
|
||||
#define _NAK = 0x15; // negative acknoledge
|
||||
#define _SYN = 0x16; // synchronous idle
|
||||
#define _CAN = 0x18; // cancel
|
||||
*/
|
||||
/* xoff - xon protocol */
|
||||
#define _SOH = 0x01; /* start of header */
|
||||
#define _EOT = 0x04; /* end of transmission */
|
||||
#define _ACK = 0x06; /* acknoledge (positive) */
|
||||
#define _DLE = 0x10; /* data link escape */
|
||||
#define _XOn = 0x11; /* transmit on */
|
||||
#define _XOff = 0x13; /* transmit off */
|
||||
#define _NAK = 0x15; /* negative acknoledge */
|
||||
#define _SYN = 0x16; /* synchronous idle */
|
||||
#define _CAN = 0x18; /* cancel */
|
||||
|
||||
static int const pacsize = 37; /* size of receive data package */
|
||||
|
||||
/* autonomy calcule */
|
||||
static double const AmpH = 40; // Amperes-hora da bateria
|
||||
static double const VbatMin = 126; // Tensão mínina das baterias
|
||||
static double const VbatNom = 144; // Tensão nominal das baterias
|
||||
static double const FM = 0.32; // Fator multiplicativo de correção da autonomia
|
||||
static double const FA = -2; // Fator aditivo de correção da autonomia
|
||||
static double const ConstInt = 250; // Consumo interno sem o carregador
|
||||
static double const Vin = 220; // Tensão de entrada
|
||||
static double const AmpH = 40; /* Amperes-hora da bateria */
|
||||
static double const VbatMin = 126; /* Tensão mínina das baterias */
|
||||
static double const VbatNom = 144; /* Tensão nominal das baterias */
|
||||
static double const FM = 0.32; /* Fator multiplicativo de correção da autonomia */
|
||||
static double const FA = -2; /* Fator aditivo de correção da autonomia */
|
||||
static double const ConstInt = 250; /* Consumo interno sem o carregador */
|
||||
static double const Vin = 220; /* Tensão de entrada */
|
||||
|
||||
static int Day, Month, Year;
|
||||
static int dian=0, mesn=0, anon=0, weekn=0;
|
||||
|
@ -93,8 +92,8 @@ static int ihour,imin, isec;
|
|||
/* char seman[4]; */
|
||||
|
||||
/* int FExpansaoBateria; */
|
||||
// internal variables
|
||||
// package handshake ariables
|
||||
/* internal variables */
|
||||
/* package handshake variables */
|
||||
/* int ContadorEstouro; */
|
||||
static bool_t detected;
|
||||
static bool_t SourceFail, Out110, RedeAnterior, OcorrenciaDeFalha;
|
||||
|
@ -125,7 +124,7 @@ static int BoostVolt, Rendimento;
|
|||
static unsigned char StatusEntrada, StatusSaida, StatusBateria;
|
||||
/* events group */
|
||||
static unsigned char EventosRede, EventosSaida, EventosBateria;
|
||||
// Grupo de Programação
|
||||
/* Grupo de Programação */
|
||||
|
||||
/* Methods */
|
||||
static void ScanReceivePack(void);
|
||||
|
@ -261,16 +260,16 @@ ScanReceivePack( void )
|
|||
if( RecPack[0] ==0xC2 )
|
||||
{
|
||||
LimInfBattSrc = 174;
|
||||
LimSupBattSrc = 192;//180????? carregador eh 180 (SCOPOS)
|
||||
LimSupBattSrc = 192;/* 180????? carregador eh 180 (SCOPOS) */
|
||||
LimInfBattInv = 174;
|
||||
LimSupBattInv = 192;//170????? (SCOPOS)
|
||||
LimSupBattInv = 192;/* 170????? (SCOPOS) */
|
||||
}
|
||||
else
|
||||
{
|
||||
LimInfBattSrc = 138;
|
||||
LimSupBattSrc = 162;//180????? carregador eh 180 (SCOPOS)
|
||||
LimSupBattSrc = 162;/* 180????? carregador eh 180 (SCOPOS) */
|
||||
LimInfBattInv = 126;
|
||||
LimSupBattInv = 156;//170????? (SCOPOS)
|
||||
LimSupBattInv = 156;/* 170????? (SCOPOS) */
|
||||
}
|
||||
|
||||
BattNonValue = 144;
|
||||
|
@ -300,10 +299,10 @@ ScanReceivePack( void )
|
|||
if( BypassOn )
|
||||
OutVoltage = ( InVoltage * 1.0 / 2 ) + 5;
|
||||
|
||||
if( SourceFail && RedeAnterior ) // falha pela primeira vez
|
||||
if( SourceFail && RedeAnterior ) /* falha pela primeira vez */
|
||||
OcorrenciaDeFalha = true;
|
||||
|
||||
if( !( SourceFail ) && !( RedeAnterior ) ) // retorno da rede
|
||||
if( !( SourceFail ) && !( RedeAnterior ) ) /* retorno da rede */
|
||||
RetornoDaRede = true;
|
||||
|
||||
if( !( SourceFail ) == RedeAnterior )
|
||||
|
@ -333,7 +332,7 @@ ScanReceivePack( void )
|
|||
RecPack[8] = 99; /* ??????????????????????????????????? */
|
||||
}
|
||||
|
||||
if( OutputOn ) // Output Status
|
||||
if( OutputOn ) /* Output Status */
|
||||
StatusSaida = 2;
|
||||
else
|
||||
StatusSaida = 1;
|
||||
|
@ -341,7 +340,7 @@ ScanReceivePack( void )
|
|||
if( OverCharge )
|
||||
StatusSaida = 3;
|
||||
|
||||
if( CriticBatt ) // Battery Status
|
||||
if( CriticBatt ) /* Battery Status */
|
||||
StatusBateria = 4;
|
||||
else
|
||||
StatusBateria = 1;
|
||||
|
@ -494,7 +493,7 @@ send_command( int cmd )
|
|||
if( i == 1)
|
||||
chk = cmd;
|
||||
else
|
||||
chk = 0x00; // 0x20;
|
||||
chk = 0x00; /* 0x20; */
|
||||
}
|
||||
|
||||
ch = chk;
|
||||
|
@ -511,7 +510,7 @@ send_command( int cmd )
|
|||
kount = 0;
|
||||
while ( kount < 5 )
|
||||
{
|
||||
/* ret = ser_send_buf_pace(upsfd, UPSDELAY, psend, sizes );// optional delay */
|
||||
/* ret = ser_send_buf_pace(upsfd, UPSDELAY, psend, sizes ); */ /* optional delay */
|
||||
|
||||
for(i=0; i < 19; i++)
|
||||
{
|
||||
|
@ -564,7 +563,7 @@ static void getbaseinfo(void)
|
|||
while ( ( !detected ) && ( j < 10 ) )
|
||||
{
|
||||
|
||||
temp[0] = 0; // flush temp buffer
|
||||
temp[0] = 0; /* flush temp buffer */
|
||||
tam = ser_get_buf_len(upsfd, temp, pacsize, 3, 0);
|
||||
if( tam == 37 )
|
||||
{
|
||||
|
@ -628,10 +627,10 @@ static void getbaseinfo(void)
|
|||
dstate_setinfo("input.transfer.high", "%03.1f", InUpLim); LimSupBattInv ?
|
||||
*/
|
||||
|
||||
dstate_addcmd("shutdown.stayoff"); // CMD_SHUT
|
||||
dstate_addcmd("shutdown.stayoff"); /* CMD_SHUT */
|
||||
/* there is no reserved words for CMD_INON and CMD_INOFF yet */
|
||||
/* dstate_addcmd("input.on"); // CMD_INON = 1 */
|
||||
/* dstate_addcmd("input.off"); // CMD_INOFF = 2 */
|
||||
/* dstate_addcmd("input.on"); */ /* CMD_INON = 1 */
|
||||
/* dstate_addcmd("input.off"); */ /* CMD_INOFF = 2 */
|
||||
dstate_addcmd("load.on"); /* CMD_OUTON = 3 */
|
||||
dstate_addcmd("load.off"); /* CMD_OUTOFF = 4 */
|
||||
dstate_addcmd("bypass.start"); /* CMD_PASSON = 5 */
|
||||
|
@ -671,7 +670,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
if (!strcasecmp(cmdname, "shutdown.stayoff"))
|
||||
{
|
||||
// shutdown now (one way)
|
||||
/* shutdown now (one way) */
|
||||
/* send_command( CMD_SHUT ); */
|
||||
sendshut();
|
||||
return STAT_INSTCMD_HANDLED;
|
||||
|
@ -679,7 +678,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
if (!strcasecmp(cmdname, "load.on"))
|
||||
{
|
||||
// liga Saida
|
||||
/* liga Saida */
|
||||
ret = send_command( 3 );
|
||||
if ( ret < 1 )
|
||||
upslogx(LOG_ERR, "send_command 3 failed");
|
||||
|
@ -688,7 +687,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
if (!strcasecmp(cmdname, "load.off"))
|
||||
{
|
||||
// desliga Saida
|
||||
/* desliga Saida */
|
||||
ret = send_command( 4 );
|
||||
if ( ret < 1 )
|
||||
upslogx(LOG_ERR, "send_command 4 failed");
|
||||
|
@ -697,7 +696,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
if (!strcasecmp(cmdname, "bypass.start"))
|
||||
{
|
||||
// liga Bypass
|
||||
/* liga Bypass */
|
||||
ret = send_command( 5 );
|
||||
if ( ret < 1 )
|
||||
upslogx(LOG_ERR, "send_command 5 failed");
|
||||
|
@ -706,7 +705,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
if (!strcasecmp(cmdname, "bypass.stop"))
|
||||
{
|
||||
// desliga Bypass
|
||||
/* desliga Bypass */
|
||||
ret = send_command( 6 );
|
||||
if ( ret < 1 )
|
||||
upslogx(LOG_ERR, "send_command 6 failed");
|
||||
|
@ -771,7 +770,7 @@ void upsdrv_shutdown(void)
|
|||
/* on line: send normal shutdown, ups will return by itself on utility */
|
||||
/* on battery: send shutdown+return, ups will cycle and return soon */
|
||||
|
||||
if (!SourceFail) // on line
|
||||
if (!SourceFail) /* on line */
|
||||
{
|
||||
printf("On line, forcing shutdown command...\n");
|
||||
send_command( CMD_SHUT );
|
||||
|
|
|
@ -484,7 +484,7 @@ bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *
|
|||
len = snprintf(buf, buf_len, "%ld", *pdu->variables->val.integer / 100);
|
||||
break;
|
||||
default:
|
||||
upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x recieved from %s",
|
||||
upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x received from %s",
|
||||
upsname?upsname:device_name, pdu->variables->type, OID);
|
||||
return FALSE;
|
||||
break;
|
||||
|
@ -524,7 +524,7 @@ bool_t nut_snmp_get_int(const char *OID, long *pval)
|
|||
value = *pdu->variables->val.integer / 100;
|
||||
break;
|
||||
default:
|
||||
upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x recieved from %s",
|
||||
upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x received from %s",
|
||||
upsname?upsname:device_name, pdu->variables->type, OID);
|
||||
return FALSE;
|
||||
break;
|
||||
|
@ -1459,7 +1459,7 @@ static int parse_mibconf_args(int numargs, char **arg)
|
|||
if (ret == FALSE)
|
||||
upslogx(LOG_ERR, "su_setvar: cannot set value %s for %s", arg[4], arg[3]);
|
||||
else
|
||||
upsdebugx(1, "su_setvar: sucessfully set %s to \"%s\"", arg[0], arg[4]);
|
||||
upsdebugx(1, "su_setvar: successfully set %s to \"%s\"", arg[0], arg[4]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -282,23 +282,12 @@ static unsigned char revertdays( unsigned char dweek )
|
|||
static int IsHour( char *strx, int qual )
|
||||
{
|
||||
|
||||
char shora[3], smin[3], sep[2];
|
||||
int hora=0, min = 0, len = 0;
|
||||
int hora=0, min = 0;
|
||||
|
||||
len = strlen( strx );
|
||||
if ( len != 5 )
|
||||
return -1;
|
||||
sscanf( strx, "%2s%1s%2s", shora, sep, smin);
|
||||
if( sep[0] != ':' )
|
||||
return -1;
|
||||
if( (!isdigit( shora[0] )) || (!isdigit( shora[1] )) )
|
||||
return -1;
|
||||
if( (!isdigit( smin[0] )) || (!isdigit( smin[1] )) )
|
||||
if ((strlen(strx) != 5) || (sscanf(strx, "%d:%d", &hora, &min) != 2)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
hora = atoi( shora );
|
||||
min = atoi( smin );
|
||||
|
||||
if( qual ) {
|
||||
dhour = hora;
|
||||
dmin = min;
|
||||
|
@ -408,7 +397,7 @@ static int IsToday( unsigned char dweek, int nweek)
|
|||
|
||||
switch ( nweek )
|
||||
{
|
||||
case 0: // sunday
|
||||
case 0: /* sunday */
|
||||
return ( ( ( dweek & 0x40 ) == 0x40 ) );
|
||||
case 1:
|
||||
return ( ( ( dweek & 0x20 ) == 0x20 ) );
|
||||
|
@ -420,7 +409,7 @@ static int IsToday( unsigned char dweek, int nweek)
|
|||
return ( ( ( dweek & 0x04 ) == 0x04 ) );
|
||||
case 5:
|
||||
return ( ( ( dweek & 0x02 ) == 0x02 ) );
|
||||
case 6: // saturday
|
||||
case 6: /* saturday */
|
||||
return ( ( ( dweek & 0x01 ) == 0x01 ) );
|
||||
}
|
||||
|
||||
|
@ -802,7 +791,7 @@ static void getbaseinfo(void)
|
|||
#else
|
||||
char DaysOfWeek[7][4]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
#endif
|
||||
char mycmd[8]; // , ch;
|
||||
char mycmd[8];
|
||||
char *str1, *str2, *str3, *str4, *strx;
|
||||
unsigned char Pacote[25];
|
||||
int i, i1=0, i2=0, j=0, tam, tpac=25;
|
||||
|
@ -871,7 +860,7 @@ static void getbaseinfo(void)
|
|||
}
|
||||
}
|
||||
|
||||
} // end prgups 1 - 2
|
||||
} /* end prgups 1 - 2 */
|
||||
|
||||
/* dummy read attempt to sync - throw it out */
|
||||
snprintf(mycmd, sizeof(mycmd), "%c%c",CMD_UPSCONT, ENDCHAR);
|
||||
|
@ -879,7 +868,7 @@ static void getbaseinfo(void)
|
|||
|
||||
/* trying detect solis model */
|
||||
while ( ( !detected ) && ( j < 20 ) ) {
|
||||
temp[0] = 0; // flush temp buffer
|
||||
temp[0] = 0; /* flush temp buffer */
|
||||
tam = ser_get_buf_len(upsfd, temp, tpac, 3, 0);
|
||||
if( tam == 25 ) {
|
||||
for( i = 0 ; i < tam ; i++ ) {
|
||||
|
@ -1011,17 +1000,17 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
{
|
||||
|
||||
if (!strcasecmp(cmdname, "shutdown.return")) {
|
||||
// shutdown and restart
|
||||
ser_send_char(upsfd, CMD_SHUTRET); // 0xDE
|
||||
// ser_send_char(upsfd, ENDCHAR);
|
||||
/* shutdown and restart */
|
||||
ser_send_char(upsfd, CMD_SHUTRET); /* 0xDE */
|
||||
/* ser_send_char(upsfd, ENDCHAR); */
|
||||
return STAT_INSTCMD_HANDLED;
|
||||
}
|
||||
|
||||
if (!strcasecmp(cmdname, "shutdown.stayoff"))
|
||||
{
|
||||
// shutdown now (one way)
|
||||
ser_send_char(upsfd, CMD_SHUT); // 0xDD
|
||||
// ser_send_char(upsfd, ENDCHAR);
|
||||
/* shutdown now (one way) */
|
||||
ser_send_char(upsfd, CMD_SHUT); /* 0xDD */
|
||||
/* ser_send_char(upsfd, ENDCHAR); */
|
||||
return STAT_INSTCMD_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -1082,7 +1071,7 @@ void upsdrv_shutdown(void)
|
|||
/* on battery: send normal shutdown, ups will return by itself on utility */
|
||||
/* on line: send shutdown+return, ups will cycle and return soon */
|
||||
|
||||
if (!SourceFail) { // on line
|
||||
if (!SourceFail) { /* on line */
|
||||
|
||||
printf("On line, sending shutdown+return command...\n");
|
||||
ser_send_char(upsfd, CMD_SHUTRET );
|
||||
|
|
|
@ -71,7 +71,10 @@ void USBFreeExactMatcher(USBDeviceMatcher_t *matcher);
|
|||
void USBFreeRegexMatcher(USBDeviceMatcher_t *matcher);
|
||||
|
||||
/* dummy USB function and macro, inspired from the Linux kernel
|
||||
* this allows USB information extraction */
|
||||
* this allows USB information extraction
|
||||
* CAUTION: only use with *valid* device identifiers, Ie the following is not
|
||||
* valid (from blazer_usb, krauler subdriver): 0x0001:0x0000
|
||||
*/
|
||||
#define USB_DEVICE(vendorID, productID) vendorID, productID
|
||||
|
||||
typedef struct {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue