/* * riello_ser.c: support for Riello serial protocol based UPSes * * A document describing the protocol implemented by this driver can be * found online at "http://www.networkupstools.org/ups-protocols/riello/PSGPSER-0104.pdf" * and "http://www.networkupstools.org/ups-protocols/riello/PSSENTR-0100.pdf". * * Copyright (C) 2012 - Elio Parisi * * 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 * * Reference of the derivative work: blazer driver */ #include "config.h" /* must be the first header */ #include #include #include "main.h" #include "serial.h" #include "timehead.h" /* // The serial driver has no need for HID structures/code currently // (maybe there is/was a plan for sharing something between siblings). // Note that HID is tied to libusb or libshut definitions at the moment. #include "hidparser.h" #include "hidtypes.h" */ #include "common.h" /* for upsdebugx() etc */ #include "riello.h" #define DRIVER_NAME "Riello serial driver" #define DRIVER_VERSION "0.07" #define DEFAULT_OFFDELAY 5 #define DEFAULT_BOOTDELAY 5 /* driver description structure */ upsdrv_info_t upsdrv_info = { DRIVER_NAME, DRIVER_VERSION, "Elio Parisi ", DRV_EXPERIMENTAL, { NULL } }; static uint8_t bufOut[BUFFER_SIZE]; static uint8_t bufIn[BUFFER_SIZE]; static uint8_t gpser_error_control; static uint8_t typeRielloProtocol; static uint8_t input_monophase; static uint8_t output_monophase; static unsigned int offdelay = DEFAULT_OFFDELAY; static unsigned int bootdelay = DEFAULT_BOOTDELAY; static TRielloData DevData; /********************************************************************** * char_read (char *bytes, size_t size, int read_timeout) * * reads size bytes from the serial port * * bytes - buffer to store the data * size - size of the data to get * read_timeout - serial timeout (in milliseconds) * * return -1 on error, -2 on timeout, nb_bytes_readen on success * *********************************************************************/ static ssize_t char_read (char *bytes, size_t size, int read_timeout) { struct timeval serial_timeout; fd_set readfs; ssize_t readen = 0; int rc = 0; FD_ZERO (&readfs); FD_SET (upsfd, &readfs); serial_timeout.tv_usec = (read_timeout % 1000) * 1000; serial_timeout.tv_sec = (read_timeout / 1000); rc = select (upsfd + 1, &readfs, NULL, NULL, &serial_timeout); if (0 == rc) return -2; /* timeout */ if (FD_ISSET (upsfd, &readfs)) { ssize_t now = read (upsfd, bytes, size - (size_t)readen); if (now < 0) { return -1; } else { readen += now; } } else { return -1; } return readen; } /********************************************************************** * serial_read (int read_timeout) * * return data one byte at a time * * read_timeout - serial timeout (in milliseconds) * * returns 0 on success, -1 on error, -2 on timeout * **********************************************************************/ static ssize_t serial_read (int read_timeout, unsigned char *readbuf) { static unsigned char cache[512]; static unsigned char *cachep = cache; static unsigned char *cachee = cache; ssize_t recv; *readbuf = '\0'; /* if still data in cache, get it */ if (cachep < cachee) { *readbuf = *cachep++; return 0; /* return (int) *cachep++; */ } recv = char_read ((char *)cache, 1, read_timeout); if ((recv == -1) || (recv == -2)) return recv; cachep = cache; cachee = cache + recv; cachep = cache; cachee = cache + recv; if (recv) { upsdebugx(5,"received: %02x", *cachep); *readbuf = *cachep++; return 0; } return -1; } static void riello_serialcomm(uint8_t* arg_bufIn, uint8_t typedev) { time_t realt, nowt; uint8_t commb = 0; realt = time(NULL); while (wait_packet) { serial_read(1000, &commb); nowt = time(NULL); commbyte = commb; riello_parse_serialport(typedev, arg_bufIn, gpser_error_control); if ((nowt - realt) > 4) break; } } static int get_ups_nominal() { uint8_t length; riello_init_serial(); length = riello_prepare_gn(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get nominal Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get nominal Ko: command not supported"); return -1; } upsdebugx (3, "Get nominal Ok: received byte %u", buf_ptr_length); riello_parse_gn(&bufIn[0], &DevData); return 0; } static int get_ups_status() { uint8_t numread, length; riello_init_serial(); length = riello_prepare_rs(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } if (input_monophase) numread = LENGTH_RS_MM; else if (output_monophase) numread = LENGTH_RS_TM; else numread = LENGTH_RS_TT; riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get status Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get status Ko: command not supported"); return -1; } upsdebugx (3, "Get status Ok: received byte %u", buf_ptr_length); riello_parse_rs(&bufIn[0], &DevData, numread); return 0; } static int get_ups_extended() { uint8_t length; riello_init_serial(); length = riello_prepare_re(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get extended Ko: bad CRC or Checksum"); return -1; } /* optonal */ if (!wait_packet && foundnak) { upsdebugx (3, "Get extended Ko: command not supported"); return 0; } upsdebugx (3, "Get extended Ok: received byte %u", buf_ptr_length); riello_parse_re(&bufIn[0], &DevData); return 0; } /* Not static, exposed via header. Not used though, currently... */ int get_ups_statuscode() { uint8_t length; riello_init_serial(); length = riello_prepare_rc(&bufOut[0], gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get statuscode Ko: bad CRC or Checksum"); return -1; } /* optional */ if (!wait_packet && foundnak) { upsdebugx (3, "Get statuscode Ko: command not supported"); return 0; } upsdebugx (3, "Get statuscode Ok: received byte %u", buf_ptr_length); riello_parse_rc(&bufIn[0], &DevData); return 0; } static int get_ups_sentr() { uint8_t length; riello_init_serial(); bufOut[0] = requestSENTR; if (requestSENTR == SENTR_EXT176) { bufOut[1] = 103; bufOut[2] = 1; bufOut[3] = 0; bufOut[4] = 24; length = 5; } else length = 1; if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get sentry Ko: bad CRC or Checksum"); return -1; } /* mandatory */ if (!wait_packet && foundnak) { upsdebugx (3, "Get sentry Ko: command not supported"); return -1; } upsdebugx (3, "Get sentry Ok: received byte %u", buf_ptr_length); riello_parse_sentr(&bufIn[0], &DevData); return 0; } static int riello_instcmd(const char *cmdname, const char *extra) { uint8_t length; uint16_t delay; const char *delay_char; if (!riello_test_bit(&DevData.StatusCode[0], 1)) { if (!strcasecmp(cmdname, "load.off")) { delay = 0; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cs(bufOut, gpser_error_control, delay); else length = riello_prepare_shutsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.off communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.off Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.off Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.off Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.off.delay")) { int ipv; delay_char = dstate_getinfo("ups.delay.shutdown"); ipv = atoi(delay_char); if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cs(bufOut, gpser_error_control, delay); else length = riello_prepare_shutsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.off delay communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.off.delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.off.delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.off delay Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on")) { delay = 0; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cr(bufOut, gpser_error_control, delay); else { length = riello_prepare_setrebsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on Ko: command not supported"); return STAT_INSTCMD_FAILED; } length = riello_prepare_rebsentr(bufOut, delay); } if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.on Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "load.on.delay")) { int ipv; delay_char = dstate_getinfo("ups.delay.reboot"); ipv = atoi(delay_char); if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cr(bufOut, gpser_error_control, delay); else { length = riello_prepare_setrebsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on delay communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } length = riello_prepare_rebsentr(bufOut, delay); } if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command load.on delay communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command load.on.delay Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command load.on.delay Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command load.on delay Ok"); return STAT_INSTCMD_HANDLED; } } else { if (!strcasecmp(cmdname, "shutdown.return")) { int ipv; delay_char = dstate_getinfo("ups.delay.shutdown"); ipv = atoi(delay_char); if (ipv < 0 || (intmax_t)ipv > (intmax_t)UINT16_MAX) return STAT_INSTCMD_FAILED; delay = (uint16_t)ipv; riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cs(bufOut, gpser_error_control, delay); else length = riello_prepare_shutsentr(bufOut, delay); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command shutdown.return communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command shutdown.return Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command shutdown.return Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command shutdown.return Ok"); return STAT_INSTCMD_HANDLED; } } if (!strcasecmp(cmdname, "shutdown.stop")) { riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_cd(bufOut, gpser_error_control); else length = riello_prepare_cancelsentr(bufOut); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command shutdown.stop communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command shutdown.stop Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command shutdown.stop Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command shutdown.stop Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.panel.start")) { riello_init_serial(); length = riello_prepare_tp(bufOut, gpser_error_control); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command test.panel.start communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command test.panel.start Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command test.panel.start Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command test.panel.start Ok"); return STAT_INSTCMD_HANDLED; } if (!strcasecmp(cmdname, "test.battery.start")) { riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) length = riello_prepare_tb(bufOut, gpser_error_control); else length = riello_prepare_tbsentr(bufOut); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Command test.battery.start communication error"); return STAT_INSTCMD_FAILED; } riello_serialcomm(&bufIn[0], typeRielloProtocol); if (!wait_packet && foundbadcrc) { upsdebugx (3, "Command battery.start Ko: bad CRC or Checksum"); return STAT_INSTCMD_FAILED; } if (!wait_packet && foundnak) { upsdebugx (3, "Command battery.start Ko: command not supported"); return STAT_INSTCMD_FAILED; } upsdebugx (3, "Command test.battery.start Ok"); return STAT_INSTCMD_HANDLED; } upslogx(LOG_NOTICE, "instcmd: unknown command [%s] [%s]", cmdname, extra); return STAT_INSTCMD_UNKNOWN; } static int start_ups_comm() { uint8_t length; upsdebugx (2, "entering start_ups_comm()\n"); riello_init_serial(); if (typeRielloProtocol == DEV_RIELLOGPSER) { length = riello_prepare_gi(&bufOut[0]); if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); } else { bufOut[0] = 192; length = 1; if (ser_send_buf(upsfd, bufOut, length) == 0) { upsdebugx (3, "Communication error while writing to port"); return -1; } riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); } if (!wait_packet && foundbadcrc) { upsdebugx (3, "Get identif Ko: bad CRC or Checksum"); return 1; } if (!wait_packet && foundnak) { upsdebugx (3, "Get identif Ko: command not supported"); return 1; } upsdebugx (3, "Get identif Ok: received byte %u", buf_ptr_length); return 0; } void upsdrv_initinfo(void) { int ret; ret = start_ups_comm(); if (ret < 0) fatalx(EXIT_FAILURE, "No communication with UPS"); else if (ret > 0) fatalx(EXIT_FAILURE, "Bad checksum or NACK"); else upsdebugx(2, "Communication with UPS established"); if (typeRielloProtocol == DEV_RIELLOGPSER) riello_parse_gi(&bufIn[0], &DevData); else riello_parse_sentr(&bufIn[0], &DevData); gpser_error_control = DevData.Identif_bytes[4]-0x30; if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '2')) input_monophase = 1; else { input_monophase = 0; dstate_setinfo("input.phases", "%u", 3); dstate_setinfo("input.phases", "%u", 3); dstate_setinfo("input.bypass.phases", "%u", 3); } if ((DevData.Identif_bytes[0] == '1') || (DevData.Identif_bytes[0] == '3')) output_monophase = 1; else { output_monophase = 0; dstate_setinfo("output.phases", "%u", 3); } dstate_setinfo("device.mfr", "RPS S.p.a."); dstate_setinfo("device.model", "%s", (unsigned char*) DevData.ModelStr); dstate_setinfo("device.serial", "%s", (unsigned char*) DevData.Identification); dstate_setinfo("device.type", "ups"); dstate_setinfo("ups.mfr", "RPS S.p.a."); dstate_setinfo("ups.model", "%s", (unsigned char*) DevData.ModelStr); dstate_setinfo("ups.serial", "%s", (unsigned char*) DevData.Identification); dstate_setinfo("ups.firmware", "%s", (unsigned char*) DevData.Version); if (typeRielloProtocol == DEV_RIELLOGPSER) { if (get_ups_nominal() == 0) { dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW); dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA); dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout); dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0); dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat); dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap); } } else { if (get_ups_sentr() == 0) { dstate_setinfo("ups.realpower.nominal", "%u", DevData.NomPowerKW); dstate_setinfo("ups.power.nominal", "%u", DevData.NomPowerKVA); dstate_setinfo("output.voltage.nominal", "%u", DevData.NominalUout); dstate_setinfo("output.frequency.nominal", "%.1f", DevData.NomFout/10.0); dstate_setinfo("battery.voltage.nominal", "%u", DevData.NomUbat); dstate_setinfo("battery.capacity", "%u", DevData.NomBatCap); } } /* commands ----------------------------------------------- */ dstate_addcmd("load.off"); dstate_addcmd("load.on"); dstate_addcmd("load.off.delay"); dstate_addcmd("load.on.delay"); dstate_addcmd("shutdown.return"); dstate_addcmd("shutdown.stop"); dstate_addcmd("test.battery.start"); dstate_setinfo("ups.delay.shutdown", "%u", offdelay); dstate_setflags("ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.shutdown", 3); dstate_setinfo("ups.delay.reboot", "%u", bootdelay); dstate_setflags("ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING); dstate_setaux("ups.delay.reboot", 3); if (typeRielloProtocol == DEV_RIELLOGPSER) dstate_addcmd("test.panel.start"); /* install handlers */ /* upsh.setvar = hid_set_value; setvar; */ upsh.instcmd = riello_instcmd; } void upsdrv_updateinfo(void) { uint8_t getextendedOK; static int countlost = 0; int stat; upsdebugx(1, "countlost %d",countlost); if (countlost > 0){ upsdebugx(1, "Communication with UPS is lost: status read failed!"); if (countlost == COUNTLOST) { dstate_datastale(); upslogx(LOG_WARNING, "Communication with UPS is lost: status read failed!"); } } if (typeRielloProtocol == DEV_RIELLOGPSER) stat = get_ups_status(); else stat = get_ups_sentr(); if (stat < 0) { if (countlost < COUNTLOST) countlost++; return; } if (typeRielloProtocol == DEV_RIELLOGPSER) { if (get_ups_extended() == 0) getextendedOK = 1; else getextendedOK = 0; } else getextendedOK = 1; if (countlost == COUNTLOST) upslogx(LOG_NOTICE, "Communication with UPS is re-established!"); dstate_setinfo("input.frequency", "%.2f", DevData.Finp/10.0); dstate_setinfo("input.bypass.frequency", "%.2f", DevData.Fbypass/10.0); dstate_setinfo("output.frequency", "%.2f", DevData.Fout/10.0); dstate_setinfo("battery.voltage", "%.1f", DevData.Ubat/10.0); if ((DevData.BatCap < 0xFFFF) && (DevData.BatTime < 0xFFFF)) { dstate_setinfo("battery.charge", "%u", DevData.BatCap); dstate_setinfo("battery.runtime", "%u", DevData.BatTime*60); } if (DevData.Tsystem < 0xFF) dstate_setinfo("ups.temperature", "%u", DevData.Tsystem); if (input_monophase) { dstate_setinfo("input.voltage", "%u", DevData.Uinp1); dstate_setinfo("input.bypass.voltage", "%u", DevData.Ubypass1); } else { dstate_setinfo("input.L1-N.voltage", "%u", DevData.Uinp1); dstate_setinfo("input.L2-N.voltage", "%u", DevData.Uinp2); dstate_setinfo("input.L3-N.voltage", "%u", DevData.Uinp3); dstate_setinfo("input.bypass.L1-N.voltage", "%u", DevData.Ubypass1); dstate_setinfo("input.bypass.L2-N.voltage", "%u", DevData.Ubypass2); dstate_setinfo("input.bypass.L3-N.voltage", "%u", DevData.Ubypass3); } if (output_monophase) { dstate_setinfo("output.voltage", "%u", DevData.Uout1); dstate_setinfo("output.power.percent", "%u", DevData.Pout1); dstate_setinfo("ups.load", "%u", DevData.Pout1); } else { dstate_setinfo("output.L1-N.voltage", "%u", DevData.Uout1); dstate_setinfo("output.L2-N.voltage", "%u", DevData.Uout2); dstate_setinfo("output.L3-N.voltage", "%u", DevData.Uout3); dstate_setinfo("output.L1.power.percent", "%u", DevData.Pout1); dstate_setinfo("output.L2.power.percent", "%u", DevData.Pout2); dstate_setinfo("output.L3.power.percent", "%u", DevData.Pout3); dstate_setinfo("ups.load", "%u", (DevData.Pout1+DevData.Pout2+DevData.Pout3)/3); } status_init(); /* AC Fail */ if (riello_test_bit(&DevData.StatusCode[0], 1)) status_set("OB"); else status_set("OL"); /* LowBatt */ if ((riello_test_bit(&DevData.StatusCode[0], 1)) && (riello_test_bit(&DevData.StatusCode[0], 0))) status_set("LB"); /* Standby */ if (!riello_test_bit(&DevData.StatusCode[0], 3)) status_set("OFF"); /* On Bypass */ if (riello_test_bit(&DevData.StatusCode[1], 3)) status_set("BYPASS"); /* Overload */ if (riello_test_bit(&DevData.StatusCode[4], 2)) status_set("OVER"); /* Buck */ if (riello_test_bit(&DevData.StatusCode[1], 0)) status_set("TRIM"); /* Boost */ if (riello_test_bit(&DevData.StatusCode[1], 1)) status_set("BOOST"); /* Replace battery */ if (riello_test_bit(&DevData.StatusCode[2], 0)) status_set("RB"); /* Charging battery */ if (riello_test_bit(&DevData.StatusCode[2], 2)) status_set("CHRG"); status_commit(); dstate_dataok(); if (getextendedOK) { dstate_setinfo("output.L1.power", "%u", DevData.Pout1VA); dstate_setinfo("output.L2.power", "%u", DevData.Pout2VA); dstate_setinfo("output.L3.power", "%u", DevData.Pout3VA); dstate_setinfo("output.L1.realpower", "%u", DevData.Pout1W); dstate_setinfo("output.L2.realpower", "%u", DevData.Pout2W); dstate_setinfo("output.L3.realpower", "%u", DevData.Pout3W); dstate_setinfo("output.L1.current", "%u", DevData.Iout1); dstate_setinfo("output.L2.current", "%u", DevData.Iout2); dstate_setinfo("output.L3.current", "%u", DevData.Iout3); } poll_interval = 2; countlost = 0; /* if (get_ups_statuscode() != 0) upsdebugx(2, "Communication is lost"); else { }*/ /* * poll_interval = 2; */ } void upsdrv_shutdown(void) __attribute__((noreturn)); void upsdrv_shutdown(void) { /* tell the UPS to shut down, then return - DO NOT SLEEP HERE */ int retry; /* maybe try to detect the UPS here, but try a shutdown even if it doesn't respond at first if possible */ /* replace with a proper shutdown function */ /* you may have to check the line status since the commands for toggling power are frequently different for OL vs. OB */ /* OL: this must power cycle the load if possible */ /* OB: the load must remain off until the power returns */ upsdebugx(2, "upsdrv Shutdown execute"); for (retry = 1; retry <= MAXTRIES; retry++) { if (riello_instcmd("shutdown.stop", NULL) != STAT_INSTCMD_HANDLED) { continue; } if (riello_instcmd("shutdown.return", NULL) != STAT_INSTCMD_HANDLED) { continue; } fatalx(EXIT_SUCCESS, "Shutting down"); } fatalx(EXIT_FAILURE, "Shutdown failed!"); } /* 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) { /* allow '-x xyzzy' */ /* addvar(VAR_FLAG, "xyzzy", "Enable xyzzy mode"); */ /* allow '-x foo=' */ /* addvar(VAR_VALUE, "foo", "Override foo setting"); */ } void upsdrv_initups(void) { upsdebugx(2, "entering upsdrv_initups()"); upsfd = ser_open(device_path); riello_comm_setup(device_path); /* probe ups type */ /* to get variables and flags from the command line, use this: * * first populate with upsdrv_buildvartable above, then... * * set flag foo : /bin/driver -x foo * set variable 'cable' to '1234' : /bin/driver -x cable=1234 * * to test flag foo in your code: * * if (testvar("foo")) * do_something(); * * to show the value of cable: * * if ((cable = getval("cable"))) * printf("cable is set to %s\n", cable); * else * printf("cable is not set!\n"); * * don't use NULL pointers - test the return result first! */ /* the upsh handlers can't be done here, as they get initialized * shortly after upsdrv_initups returns to main. */ /* don't try to detect the UPS here */ /* initialise communication */ } void upsdrv_cleanup(void) { /* free(dynamic_mem); */ ser_close(upsfd, device_path); } void riello_comm_setup(const char *port) { uint8_t length; upsdebugx(2, "set baudrate 9600"); ser_set_speed(upsfd, device_path, B9600); upsdebugx(2, "try to detect SENTR"); riello_init_serial(); bufOut[0] = 192; ser_send_buf(upsfd, bufOut, 1); riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); if (buf_ptr_length == 103) { typeRielloProtocol = DEV_RIELLOSENTRY; upslogx(LOG_INFO, "Connected to UPS SENTR on %s with baudrate %d", port, 9600); return; } upsdebugx(2, "try to detect GPSER"); riello_init_serial(); length = riello_prepare_gi(&bufOut[0]); ser_send_buf(upsfd, bufOut, length); riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && !foundbadcrc && !foundnak) { typeRielloProtocol = DEV_RIELLOGPSER; upslogx(LOG_INFO, "Connected to UPS GPSER on %s with baudrate %d", port, 9600); return; } upsdebugx(2, "set baudrate 1200"); ser_set_speed(upsfd, device_path, B1200); upsdebugx(2, "try to detect SENTR"); riello_init_serial(); bufOut[0] = 192; ser_send_buf(upsfd, bufOut, 1); riello_serialcomm(&bufIn[0], DEV_RIELLOSENTRY); if (buf_ptr_length == 103) { typeRielloProtocol = DEV_RIELLOSENTRY; upslogx(LOG_INFO, "Connected to UPS SENTR on %s with baudrate %d", port, 1200); return; } upsdebugx(2, "try to detect GPSER"); riello_init_serial(); length = riello_prepare_gi(&bufOut[0]); ser_send_buf(upsfd, bufOut, length); riello_serialcomm(&bufIn[0], DEV_RIELLOGPSER); if (!wait_packet && !foundbadcrc && !foundnak) { typeRielloProtocol = DEV_RIELLOGPSER; upslogx(LOG_INFO, "Connected to UPS GPSER on %s with baudrate %d", port, 1200); return; } fatalx(EXIT_FAILURE, "Can't connect to the UPS on port %s!\n", port); }