/* liebert-esp2.c - driver for Liebert UPS, using the ESP-II protocol * * Copyright (C) * 2009 Richard Gregory * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "main.h" #include "serial.h" #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.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); /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Richard Gregory \n" \ "Robert Jobbagy 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, 6); if (ret < 8) { upslogx(LOG_ERR, "Failed reading bitfield #1"); dstate_datastale(); return; } if (reply[5] & (1<<0)) { /* ON_BATTERY */ status_set("OB"); } else { status_set("OL"); } val = dstate_getinfo("battery.current"); if (val) { if (atof(val) > 0.05) { status_set("CHRG"); } if (atof(val) < -0.05) { status_set("DISCHRG"); } } ret = do_command(cmd_bitfield2, reply, 6); if (ret < 8) { upslogx(LOG_ERR, "Failed reading bitfield #2"); dstate_datastale(); return; } if (reply[6] & (1<<0)) { /* ON_BYPASS */ status_set("BYPASS"); } if (reply[6] & (1<<5)) { /* REPLACE_BATTERY */ status_set("RB"); } if (reply[6] & (1<<6)) { /* BOOST_ON */ status_set("BOOST"); } if (reply[5] & (1<<1)) { /* BUCK_ON */ status_set("TRIM"); } ret = do_command(cmd_bitfield3, reply, 6); if (ret < 8) { upslogx(LOG_ERR, "Failed reading bitfield #3"); dstate_datastale(); return; } if (reply[6] & (1<<0) ) { /* UPS_OVERLOAD */ status_set("OVER"); } if (reply[6] & (1<<5) ) { /* LOW_BATTERY */ status_set("LB"); } status_commit(); dstate_dataok(); } void upsdrv_shutdown(void) { 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) { /* if (!strcasecmp(cmdname, "test.battery.stop")) { ser_send_buf(upsfd, ...); return STAT_INSTCMD_HANDLED; } */ upslogx(LOG_NOTICE, "instcmd: unknown command [%s]", cmdname); return STAT_INSTCMD_UNKNOWN; } static int setvar(const char *varname, const char *val) { /* if (!strcasecmp(varname, "ups.test.interval")) { ser_send_buf(upsfd, ...); return STAT_SET_HANDLED; } */ upslogx(LOG_NOTICE, "setvar: unknown variable [%s]", varname); return STAT_SET_UNKNOWN; } void upsdrv_help(void) { } /* list flags and values that you want to receive via -x */ void upsdrv_makevartable(void) { addvar (VAR_VALUE, "baudrate", "serial line speed"); } void upsdrv_initups(void) { const char *val = getval("baudrate"); speed_t baudrate = B2400; if (val) { switch (atoi(val)) { case 1200: baudrate = B1200; break; case 2400: baudrate = B2400; break; case 4800: baudrate = B4800; break; case 9600: baudrate = B9600; break; case 19200: baudrate = B19200; break; default: fatalx(EXIT_FAILURE, "Baudrate [%s] unsupported", val); } } upsfd = ser_open(device_path); ser_set_speed(upsfd, device_path, baudrate); } void upsdrv_cleanup(void) { ser_close(upsfd, device_path); }