Imported Upstream version 2.6.4
This commit is contained in:
parent
fad6ced6f6
commit
fefe62b2bd
257 changed files with 6020 additions and 1394 deletions
132
drivers/bcmxcp.c
132
drivers/bcmxcp.c
|
|
@ -6,8 +6,10 @@
|
|||
* emes -at- geomer.de *
|
||||
* All rights reserved.*
|
||||
|
||||
Copyright (C) 2004 Kjell Claesson <kjell.claesson-at-epost.tidanet.se>
|
||||
and Tore Ørpetveit <tore-at-orpetveit.net>
|
||||
Copyright (C)
|
||||
2004 Kjell Claesson <kjell.claesson-at-epost.tidanet.se>
|
||||
2004 Tore Ørpetveit <tore-at-orpetveit.net>
|
||||
2011 - 2012 Arnaud Quette <ArnaudQuette@Eaton.com>
|
||||
|
||||
Thanks to Tore Ørpetveit <tore-at-orpetveit.net> that sent me the
|
||||
manuals for bcm/xcp.
|
||||
|
|
@ -124,7 +126,7 @@ TODO List:
|
|||
#include "bcmxcp.h"
|
||||
|
||||
#define DRIVER_NAME "BCMXCP UPS driver"
|
||||
#define DRIVER_VERSION "0.25"
|
||||
#define DRIVER_VERSION "0.26"
|
||||
|
||||
#define MAX_NUT_NAME_LENGTH 128
|
||||
#define NUT_OUTLET_POSITION 7
|
||||
|
|
@ -157,6 +159,7 @@ static int init_outlet(unsigned char len);
|
|||
static int instcmd(const char *cmdname, const char *extra);
|
||||
static int setvar (const char *varname, const char *val);
|
||||
|
||||
static const char *nut_find_infoval(info_lkp_t *xcp2info, const double value);
|
||||
|
||||
const char *FreqTol[3] = {"+/-2%", "+/-5%", "+/-7"};
|
||||
const char *ABMStatus[4] = {"Charging", "Discharging", "Floating", "Resting"};
|
||||
|
|
@ -166,6 +169,32 @@ int nphases = 0;
|
|||
int outlet_block_len = 0;
|
||||
const char *cpu_name[5] = {"Cont:", "Inve:", "Rect:", "Netw:", "Disp:"};
|
||||
|
||||
|
||||
|
||||
/* Battery test results */
|
||||
info_lkp_t batt_test_info[] = {
|
||||
{ 0, "No test initiated", NULL },
|
||||
{ 1, "In progress", NULL },
|
||||
{ 2, "Done and passed", NULL },
|
||||
{ 3, "Aborted", NULL },
|
||||
{ 4, "Done and error", NULL },
|
||||
{ 5, "Test scheduled", NULL },
|
||||
/* Not sure about the meaning of the below ones! */
|
||||
{ 6, NULL, NULL }, /* The string was present but it has now been removed */
|
||||
{ 7, NULL, NULL }, /* The string was not installed at the last power up */
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
||||
/* allocate storage for shared variables (extern in bcmxcp.h) */
|
||||
BCMXCP_METER_MAP_ENTRY_t
|
||||
bcmxcp_meter_map[BCMXCP_METER_MAP_MAX];
|
||||
BCMXCP_ALARM_MAP_ENTRY_t
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_MAP_MAX];
|
||||
BCMXCP_STATUS_t
|
||||
bcmxcp_status;
|
||||
|
||||
|
||||
/* get_word function from nut driver metasys.c */
|
||||
int get_word(const unsigned char *buffer) /* return an integer reading a word in the supplied buffer */
|
||||
{
|
||||
|
|
@ -583,7 +612,12 @@ void init_alarm_map()
|
|||
bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_ON_COMMAND].alarm_desc = "CHARGER_ON_COMMAND";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_CHARGER_OFF_COMMAND].alarm_desc = "CHARGER_OFF_COMMAND";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_UPS_NORMAL].alarm_desc = "UPS_NORMAL";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_INVERTER_PHASE_ROTATION].alarm_desc = "INVERTER_PHASE_ROTATION";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_UPS_OFF].alarm_desc = "UPS_OFF";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_EXTERNAL_COMMUNICATION_FAILURE].alarm_desc = "EXTERNAL_COMMUNICATION_FAILURE";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_TEST_INPROGRESS].alarm_desc = "BATTERY_TEST_INPROGRESS";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_SYSTEM_TEST_INPROGRESS].alarm_desc = "SYSTEM_TEST_INPROGRESS";
|
||||
bcmxcp_alarm_map[BCMXCP_ALARM_BATTERY_TEST_ABORTED].alarm_desc = "BATTERY_TEST_ABORTED";
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -936,7 +970,7 @@ void init_config(void)
|
|||
int voltage = 0, res, len;
|
||||
char sValue[17];
|
||||
|
||||
res = command_read_sequence(PW_CONFIG_BLOC_REQ, answer);
|
||||
res = command_read_sequence(PW_CONFIG_BLOCK_REQ, answer);
|
||||
if (res <= 0)
|
||||
fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups");
|
||||
|
||||
|
|
@ -1104,12 +1138,12 @@ void upsdrv_initinfo(void)
|
|||
|
||||
dstate_setinfo("ups.firmware", "%s", pTmp);
|
||||
|
||||
free(pTmp);
|
||||
|
||||
/* Increment index to point at end of CPU bytes. */
|
||||
iIndex += len * 2;
|
||||
}
|
||||
|
||||
free(pTmp);
|
||||
|
||||
/* Get rating in kVA, if present */
|
||||
if ((iRating = answer[iIndex++]) > 0)
|
||||
iRating *= 1000;
|
||||
|
|
@ -1244,6 +1278,8 @@ void upsdrv_updateinfo(void)
|
|||
char sValue[128];
|
||||
int iIndex, res;
|
||||
float output, max_output, fValue = 0.0f;
|
||||
int batt_status = 0;
|
||||
const char *nutvalue;
|
||||
|
||||
/* Get info from UPS */
|
||||
res = command_read_sequence(PW_METER_BLOCK_REQ, answer);
|
||||
|
|
@ -1332,6 +1368,14 @@ void upsdrv_updateinfo(void)
|
|||
if (iIndex == BCMXCP_ALARM_BATTERY_LOW) {
|
||||
bcmxcp_status.alarm_low_battery = 1;
|
||||
}
|
||||
|
||||
if (iIndex == BCMXCP_ALARM_BATTERY_TEST_FAILED) {
|
||||
bcmxcp_status.alarm_replace_battery = 1;
|
||||
}
|
||||
|
||||
if (iIndex == BCMXCP_ALARM_BATTERY_NEEDS_SERVICE) {
|
||||
bcmxcp_status.alarm_replace_battery = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1404,10 +1448,38 @@ void upsdrv_updateinfo(void)
|
|||
status_set("OB");
|
||||
if (bcmxcp_status.alarm_low_battery)
|
||||
status_set("LB");
|
||||
if (bcmxcp_status.alarm_replace_battery)
|
||||
status_set("RB");
|
||||
|
||||
status_commit();
|
||||
}
|
||||
|
||||
/* Get battery info from UPS, if exist */
|
||||
res = command_read_sequence(PW_BATTERY_REQ, answer);
|
||||
if (res <= 0)
|
||||
{
|
||||
upsdebugx(1, "Failed to read Battery Status from UPS");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only parse the status (first byte)
|
||||
* Powerware 5115 RM output:
|
||||
* 02 00 78 1d 42 00 e0 17 42 1e 00 00 00 00 00 00 00 00 00 01 03
|
||||
* Powerware 9130 output:
|
||||
* 03 0a d7 25 42 0a d7 25 42 00 9a 19 6d 43 cd cc 4c 3e 01 00 01 03
|
||||
*/
|
||||
upsdebug_hex(2, "Battery Status", answer, res);
|
||||
batt_status = answer[0];
|
||||
|
||||
if ((nutvalue = nut_find_infoval(batt_test_info, batt_status)) != NULL) {
|
||||
dstate_setinfo("ups.test.result", "%s", nutvalue);
|
||||
upsdebugx(2, "Battery Status = %s (%i)", nutvalue, batt_status);
|
||||
}
|
||||
else {
|
||||
upsdebugx(1, "Failed to extract Battery Status from answer");
|
||||
}
|
||||
}
|
||||
|
||||
dstate_dataok();
|
||||
}
|
||||
|
||||
|
|
@ -1428,7 +1500,7 @@ void upsdrv_shutdown(void)
|
|||
it doesn't respond at first if possible */
|
||||
send_write_command(AUTHOR, 4);
|
||||
|
||||
sleep(1); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
|
||||
cbuf[0] = PW_LOAD_OFF_RESTART;
|
||||
cbuf[1] = (unsigned char)(bcmxcp_status.shutdowndelay & 0x00ff); /* "delay" sec delay for shutdown, */
|
||||
|
|
@ -1493,12 +1565,12 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
) {
|
||||
send_write_command(AUTHOR, 4);
|
||||
|
||||
sleep(1); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
|
||||
/* Get the shutdown delay, if any */
|
||||
snprintf(varname, sizeof(varname)-1, "outlet.%c.delay.shutdown", cmdname[7]);
|
||||
if ((varvalue = dstate_getinfo(varname)) != NULL) {
|
||||
sddelay = atoi(dstate_getinfo(varname));
|
||||
sddelay = atoi(varvalue);
|
||||
}
|
||||
|
||||
cbuf[0] = PW_LOAD_OFF_RESTART;
|
||||
|
|
@ -1546,7 +1618,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
if (!strcasecmp(cmdname, "shutdown.return")) {
|
||||
send_write_command(AUTHOR, 4);
|
||||
|
||||
sleep(1); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
|
||||
cbuf[0] = PW_LOAD_OFF_RESTART;
|
||||
cbuf[1] = (unsigned char)(bcmxcp_status.shutdowndelay & 0x00ff); /* "delay" sec delay for shutdown, */
|
||||
|
|
@ -1590,7 +1662,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
if (!strcasecmp(cmdname, "shutdown.stayoff")) {
|
||||
send_write_command(AUTHOR, 4);
|
||||
|
||||
sleep(1); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
|
||||
res = command_read_sequence(PW_UPS_OFF, answer);
|
||||
if (res <= 0) {
|
||||
|
|
@ -1626,10 +1698,13 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
}
|
||||
|
||||
/* Note: test result will be parsed from Battery status block,
|
||||
* part of the update loop, and published into ups.test.result
|
||||
*/
|
||||
if (!strcasecmp(cmdname, "test.battery.start")) {
|
||||
send_write_command(AUTHOR, 4);
|
||||
|
||||
sleep(1); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
|
||||
cbuf[0] = PW_INIT_BAT_TEST;
|
||||
cbuf[1] = 0x0A; /* 10 sec start delay for test.*/
|
||||
|
|
@ -1665,12 +1740,6 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
break;
|
||||
}
|
||||
}
|
||||
/* Get test info from UPS ?
|
||||
Should we wait for 50 sec and get the
|
||||
answer from the test.
|
||||
Or return, as we may lose line power
|
||||
and need to do a shutdown.*/
|
||||
|
||||
}
|
||||
|
||||
upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname);
|
||||
|
|
@ -1715,8 +1784,7 @@ int setvar (const char *varname, const char *val)
|
|||
}
|
||||
|
||||
send_write_command(AUTHOR, 4);
|
||||
/* Need to. Have to wait at least 0.25 sec max 16 sec */
|
||||
sleep (1);
|
||||
sleep(PW_SLEEP); /* Need to. Have to wait at least 0,25 sec max 16 sec */
|
||||
|
||||
outlet_num = varname[NUT_OUTLET_POSITION] - '0';
|
||||
if (outlet_num < 1 || outlet_num > 9) {
|
||||
|
|
@ -1781,4 +1849,28 @@ int setvar (const char *varname, const char *val)
|
|||
return STAT_SET_INVALID;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Extracted from usbhid-ups.c *
|
||||
*******************************/
|
||||
|
||||
/* find the NUT value matching that XCP Item value */
|
||||
static const char *nut_find_infoval(info_lkp_t *xcp2info, const double value)
|
||||
{
|
||||
info_lkp_t *info_lkp;
|
||||
|
||||
/* if a conversion function is defined, use 'value' as argument for it */
|
||||
if (xcp2info->fun != NULL) {
|
||||
return xcp2info->fun(value);
|
||||
}
|
||||
|
||||
/* use 'value' as an index for a lookup in an array */
|
||||
for (info_lkp = xcp2info; info_lkp->nut_value != NULL; info_lkp++) {
|
||||
if (info_lkp->xcp_value == (long)value) {
|
||||
upsdebugx(5, "nut_find_infoval: found %s (value: %ld)", info_lkp->nut_value, (long)value);
|
||||
return info_lkp->nut_value;
|
||||
}
|
||||
}
|
||||
|
||||
upsdebugx(3, "hu_find_infoval: no matching INFO_* value for this XCP value (%g)", value);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue