/* mge-hid.c - data to monitor MGE UPS SYSTEMS HID (USB and serial) devices * * Copyright (C) 2003 - 2005 * Arnaud Quette * * Sponsored by MGE UPS SYSTEMS * * 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 "usbhid-ups.h" #include "mge-hid.h" #include "extstate.h" /* for ST_FLAG_STRING */ #include "dstate.h" /* for STAT_INSTCMD_HANDLED */ #include "main.h" /* for getval() */ #include "common.h" #define MGE_HID_VERSION "MGE HID 1.0" #define MGE_VENDORID 0x0463 /* --------------------------------------------------------------- */ /* Vendor-specific usage table */ /* --------------------------------------------------------------- */ /* MGE UPS SYSTEMS usage table */ static usage_lkp_t mge_usage_lkp[] = { { "Undefined", 0xffff0000 }, { "STS", 0xffff0001 }, { "Environment", 0xffff0002 }, /* 0xffff0003-0xffff000f => Reserved */ { "Phase", 0xffff0010 }, { "PhaseID", 0xffff0011 }, { "Chopper", 0xffff0012 }, { "ChopperID", 0xffff0013 }, { "Inverter", 0xffff0014 }, { "InverterID", 0xffff0015 }, { "Rectifier", 0xffff0016 }, { "RectifierID", 0xffff0017 }, { "LCMSystem", 0xffff0018 }, { "LCMSystemID", 0xffff0019 }, { "LCMAlarm", 0xffff001a }, { "LCMAlarmID", 0xffff001b }, { "HistorySystem", 0xffff001c }, { "HistorySystemID", 0xffff001d }, { "Event", 0xffff001e }, { "EventID", 0xffff001f }, { "CircuitBreaker", 0xffff0020 }, { "TransferForbidden", 0xffff0021 }, { "OverallAlarm", 0xffff0022 }, { "Dephasing", 0xffff0023 }, { "BypassBreaker", 0xffff0024 }, { "PowerModule", 0xffff0025 }, { "PowerRate", 0xffff0026 }, { "PowerSource", 0xffff0027 }, { "CurrentPowerSource", 0xffff0028 }, { "RedundancyLevel", 0xffff0029 }, { "RedundancyLost", 0xffff002a }, { "NotificationStatus", 0xffff002b }, /* 0xffff002c-0xffff003f => Reserved */ { "SwitchType", 0xffff0040 }, { "ConverterType", 0xffff0041 }, { "FrequencyConverterMode", 0xffff0042 }, { "AutomaticRestart", 0xffff0043 }, { "ForcedReboot", 0xffff0044 }, { "TestPeriod", 0xffff0045 }, { "EnergySaving", 0xffff0046 }, { "StartOnBattery", 0xffff0047 }, { "Schedule", 0xffff0048 }, { "DeepDischargeProtection", 0xffff0049 }, { "ShortCircuit", 0xffff004a }, { "ExtendedVoltageMode", 0xffff004b }, { "SensitivityMode", 0xffff004c }, { "RemainingCapacityLimitSetting", 0xffff004d }, { "ExtendedFrequencyMode", 0xffff004e }, { "FrequencyConverterModeSetting", 0xffff004f }, { "LowVoltageBoostTransfer", 0xffff0050 }, { "HighVoltageBoostTransfer", 0xffff0051 }, { "LowVoltageBuckTransfer", 0xffff0052 }, { "HighVoltageBuckTransfer", 0xffff0053 }, { "OverloadTransferEnable", 0xffff0054 }, { "OutOfToleranceTransferEnable", 0xffff0055 }, { "ForcedTransferEnable", 0xffff0056 }, { "LowVoltageBypassTransfer", 0xffff0057 }, { "HighVoltageBypassTransfer", 0xffff0058 }, { "FrequencyRangeBypassTransfer", 0xffff0059 }, { "LowVoltageEcoTransfer", 0xffff005a }, { "HighVoltageEcoTransfer", 0xffff005b }, { "FrequencyRangeEcoTransfer", 0xffff005c }, { "ShutdownTimer", 0xffff005d }, { "StartupTimer", 0xffff005e }, { "RestartLevel", 0xffff005f }, { "PhaseOutOfRange", 0xffff0060 }, { "CurrentLimitation", 0xffff0061 }, { "ThermalOverload", 0xffff0062 }, { "SynchroSource", 0xffff0063 }, { "FuseFault", 0xffff0064 }, { "ExternalProtectedTransfert", 0xffff0065 }, { "ExternalForcedTransfert", 0xffff0066 }, { "Compensation", 0xffff0067 }, { "EmergencyStop", 0xffff0068 }, { "PowerFactor", 0xffff0069 }, { "PeakFactor", 0xffff006a }, { "ChargerType", 0xffff006b }, { "HighPositiveDCBusVoltage", 0xffff006c }, { "LowPositiveDCBusVoltage", 0xffff006d }, { "HighNegativeDCBusVoltage", 0xffff006e }, { "LowNegativeDCBusVoltage", 0xffff006f }, { "FrequencyRangeTransfer", 0xffff0070 }, { "WiringFaultDetection", 0xffff0071 }, { "ControlStandby", 0xffff0072 }, { "ShortCircuitTolerance", 0xffff0073 }, { "VoltageTooHigh", 0xffff0074 }, { "VoltageTooLow", 0xffff0075 }, { "DCBusUnbalanced", 0xffff0076 }, { "FanFailure", 0xffff0077 }, { "WiringFault", 0xffff0078 }, /* 0xffff0079-0xffff007f => Reserved */ { "Sensor", 0xffff0080 }, { "LowHumidity", 0xffff0081 }, { "HighHumidity", 0xffff0082 }, { "LowTemperature", 0xffff0083 }, { "HighTemperature", 0xffff0084 }, /* 0xffff0085-0xffff008f => Reserved */ { "Count", 0xffff0090 }, { "Timer", 0xffff0091 }, { "Interval", 0xffff0092 }, { "TimerExpired", 0xffff0093 }, { "Mode", 0xffff0094 }, { "Country", 0xffff0095 }, { "State", 0xffff0096 }, { "Time", 0xffff0097 }, { "Code", 0xffff0098 }, { "DataValid", 0xffff0099 }, /* 0xffff009a-0xffff00df => Reserved */ { "COPIBridge", 0xffff00e0 }, /* 0xffff00e1-0xffff00ef => Reserved */ { "iModel", 0xffff00f0 }, { "iVersion", 0xffff00f1 }, /* 0xffff00f2-0xffff00ff => Reserved */ /* MGE indexed collections */ { "[1]", 0x00ff0001 }, { "[2]", 0x00ff0002 }, { "[3]", 0x00ff0003 }, { "[4]", 0x00ff0004 }, /* end of table */ { "\0", 0x00000000 } }; static usage_tables_t mge_utab[] = { mge_usage_lkp, hid_usage_lkp, NULL, }; /* --------------------------------------------------------------- */ /* Model Name formating entries */ /* --------------------------------------------------------------- */ static models_name_t mge_model_names [] = { /* Ellipse models */ { "ELLIPSE", "300", -1, "ellipse 300" }, { "ELLIPSE", "500", -1, "ellipse 500" }, { "ELLIPSE", "650", -1, "ellipse 650" }, { "ELLIPSE", "800", -1, "ellipse 800" }, { "ELLIPSE", "1200", -1, "ellipse 1200" }, /* Ellipse Premium models */ { "ellipse", "PR500", -1, "ellipse premium 500" }, { "ellipse", "PR650", -1, "ellipse premium 650" }, { "ellipse", "PR800", -1, "ellipse premium 800" }, { "ellipse", "PR1200", -1, "ellipse premium 1200" }, /* Ellipse "Pro" */ { "ELLIPSE", "600", -1, "Ellipse 600" }, { "ELLIPSE", "750", -1, "Ellipse 750" }, { "ELLIPSE", "1000", -1, "Ellipse 1000" }, { "ELLIPSE", "1500", -1, "Ellipse 1500" }, /* Ellipse "MAX" */ { "Ellipse MAX", "600", -1, "Ellipse MAX 600" }, { "Ellipse MAX", "850", -1, "Ellipse MAX 850" }, { "Ellipse MAX", "1100", -1, "Ellipse MAX 1100" }, { "Ellipse MAX", "1500", -1, "Ellipse MAX 1500" }, /* Protection Center */ { "PROTECTIONCENTER", "420", -1, "Protection Center 420" }, { "PROTECTIONCENTER", "500", -1, "Protection Center 500" }, { "PROTECTIONCENTER", "675", -1, "Protection Center 675" }, /* Evolution models */ { "Evolution", "500", -1, "Pulsar Evolution 500" }, { "Evolution", "800", -1, "Pulsar Evolution 800" }, { "Evolution", "1100", -1, "Pulsar Evolution 1100" }, { "Evolution", "1500", -1, "Pulsar Evolution 1500" }, { "Evolution", "2200", -1, "Pulsar Evolution 2200" }, { "Evolution", "3000", -1, "Pulsar Evolution 3000" }, { "Evolution", "3000XL", -1, "Pulsar Evolution 3000 XL" }, /* Newer Evolution models */ { "Evolution", "650", -1, "Evolution 650" }, { "Evolution", "850", -1, "Evolution 850" }, { "Evolution", "1150", -1, "Evolution 1150" }, { "Evolution", "S 1250", -1, "Evolution S 1250" }, { "Evolution", "1550", -1, "Evolution 1550" }, { "Evolution", "S 1750", -1, "Evolution S 1750" }, { "Evolution", "2000", -1, "Evolution 2000" }, { "Evolution", "S 2500", -1, "Evolution S 2500" }, { "Evolution", "S 3000", -1, "Evolution S 3000" }, /* Pulsar M models */ { "PULSAR M", "2200", -1, "Pulsar M 2200" }, { "PULSAR M", "3000", -1, "Pulsar M 3000" }, { "PULSAR M", "3000 XL", -1, "Pulsar M 3000 XL" }, /* Pulsar models */ { "Pulsar", "700", -1, "Pulsar 700" }, { "Pulsar", "1000", -1, "Pulsar 1000" }, { "Pulsar", "1500", -1, "Pulsar 1500" }, { "Pulsar", "1000 RT2U", -1, "Pulsar 1000 RT2U" }, { "Pulsar", "1500 RT2U", -1, "Pulsar 1500 RT2U" }, /* Pulsar MX models */ { "PULSAR", "MX4000", -1, "Pulsar MX 4000 RT" }, { "PULSAR", "MX5000", -1, "Pulsar MX 5000 RT" }, /* NOVA models */ { "NOVA AVR", "600", -1, "NOVA 600 AVR" }, { "NOVA AVR", "1100", -1, "NOVA 1100 AVR" }, /* EXtreme C (EMEA) */ { "EXtreme", "700C", -1, "Pulsar EXtreme 700C" }, { "EXtreme", "1000C", -1, "Pulsar EXtreme 1000C" }, { "EXtreme", "1500C", -1, "Pulsar EXtreme 1500C" }, { "EXtreme", "1500CCLA", -1, "Pulsar EXtreme 1500C CLA" }, { "EXtreme", "2200C", -1, "Pulsar EXtreme 2200C" }, { "EXtreme", "3200C", -1, "Pulsar EXtreme 3200C" }, /* EXtreme C (USA, aka "EX RT") */ { "EX", "700RT", -1, "Pulsar EX 700 RT" }, { "EX", "1000RT", -1, "Pulsar EX 1000 RT" }, { "EX", "1500RT", -1, "Pulsar EX 1500 RT" }, { "EX", "2200RT", -1, "Pulsar EX 2200 RT" }, { "EX", "3200RT", -1, "Pulsar EX 3200 RT" }, /* Comet EX RT three phased */ { "EX", "5RT31", -1, "EX 5 RT 3:1" }, { "EX", "7RT31", -1, "EX 7 RT 3:1" }, { "EX", "11RT31", -1, "EX 11 RT 3:1" }, /* Comet EX RT mono phased */ { "EX", "5RT", -1, "EX 5 RT" }, { "EX", "7RT", -1, "EX 7 RT" }, { "EX", "11RT", -1, "EX 11 RT" }, /* Galaxy 3000 */ { "GALAXY", "3000_10", -1, "Galaxy 3000 10 kVA" }, { "GALAXY", "3000_15", -1, "Galaxy 3000 15 kVA" }, { "GALAXY", "3000_20", -1, "Galaxy 3000 20 kVA" }, { "GALAXY", "3000_30", -1, "Galaxy 3000 30 kVA" }, /* FIXME: To be completed (Comet, Galaxy, Esprit, ...) */ /* end of structure. */ { NULL, NULL, -1, "Generic MGE HID model" } }; /* --------------------------------------------------------------- */ /* Data lookup table (HID <-> NUT) */ /* --------------------------------------------------------------- */ static hid_info_t mge_hid2nut[] = { /* Server side variables */ { "driver.version.internal", ST_FLAG_STRING, 5, NULL, NULL, DRIVER_VERSION, HU_FLAG_ABSENT | HU_FLAG_OK, NULL }, { "driver.version.data", ST_FLAG_STRING, 11, NULL, NULL, MGE_HID_VERSION, HU_FLAG_ABSENT | HU_FLAG_OK, NULL }, /* Battery page */ { "battery.charge", 0, 1, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", HU_FLAG_OK, NULL }, { "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.RemainingCapacityLimitSetting", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "battery.charge.low", ST_FLAG_STRING, 5, "UPS.PowerSummary.RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_STATIC , NULL }, /* Read only */ { "battery.charge.restart", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.PowerSummary.RestartLevel", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", HU_FLAG_OK, NULL }, { "battery.temperature", 0, 0, "UPS.BatterySystem.Battery.Temperature", NULL, "%.1f", HU_FLAG_OK, NULL }, { "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_OK | HU_FLAG_STATIC, stringid_conversion }, { "battery.voltage", 0, 0, "UPS.PowerSummary.Voltage", NULL, "%.1f", HU_FLAG_OK, NULL }, { "battery.voltage.nominal", 0, 0, "UPS.BatterySystem.ConfigVoltage", NULL, "%.1f", HU_FLAG_OK, NULL }, /* UPS page */ { "ups.load", 0, 1, "UPS.PowerSummary.PercentLoad", NULL, "%.0f", HU_FLAG_OK, NULL }, { "ups.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL}, { "ups.delay.reboot", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.DelayBeforeReboot", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL}, { "ups.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.DelayBeforeStartup", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL}, { "ups.test.result", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "%s", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, &test_read_info[0] }, { "ups.test.interval", ST_FLAG_RW | ST_FLAG_STRING, 8, "UPS.BatterySystem.Battery.TestPeriod", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "ups.beeper.status", 0, 1, "UPS.PowerSummary.AudibleAlarmControl", NULL, "%s", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, &beeper_info[0] }, { "ups.temperature", 0, 0, "UPS.PowerSummary.Temperature", NULL, "%.1f", HU_FLAG_OK, NULL }, /* FIXME: miss ups.power */ { "ups.power.nominal", ST_FLAG_STRING, 5, "UPS.Flow.[4].ConfigApparentPower", NULL, "%.0f",HU_FLAG_OK, NULL }, /* Special case: ups.status */ { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_QUICK_POLL, &online_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.Discharging", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_QUICK_POLL, &discharging_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.Charging", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_QUICK_POLL, &charging_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.ShutdownImminent", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_QUICK_POLL, &shutdownimm_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.BelowRemainingCapacityLimit", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_QUICK_POLL, &lowbatt_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.Overload", NULL, "%.0f", HU_FLAG_OK, &overload_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, "%.0f", HU_FLAG_OK, &replacebatt_info[0] }, { "ups.status", 0, 1, "UPS.PowerConverter.Input.[1].PresentStatus.Buck", NULL, "%.0f", HU_FLAG_OK, &trim_info[0] }, { "ups.status", 0, 1, "UPS.PowerConverter.Input.[1].PresentStatus.Boost", NULL, "%.0f", HU_FLAG_OK, &boost_info[0] }, { "ups.status", 0, 1, "UPS.PowerSummary.PresentStatus.Good", NULL, "%.0f", HU_FLAG_OK, &off_info[0] }, /* FIXME: extend ups.status for BYPASS: */ /* Manual bypass */ { "ups.status", 0, 1, "UPS.PowerConverter.Input[4].PresentStatus.Used", NULL, "%.0f", HU_FLAG_OK, &bypass_info[0] }, /* Automatic bypass */ { "ups.status", 0, 1, "UPS.PowerConverter.Input[2].PresentStatus.Used", NULL, "%.0f", HU_FLAG_OK, &bypass_info[0] }, /* Input page */ { "input.voltage", 0, 0, "UPS.PowerConverter.Input.[1].Voltage", NULL, "%.1f", HU_FLAG_OK, NULL }, { "input.frequency", 0, 0, "UPS.PowerConverter.Input.[1].Frequency", NULL, "%.1f", HU_FLAG_OK, NULL }, /* same as "input.transfer.boost.low" */ { "input.transfer.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageTransfer", NULL, "%.1f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.boost.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageBoostTransfer",NULL, "%.1f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.boost.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageBoostTransfer", NULL, "%.1f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.trim.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.LowVoltageBuckTransfer", NULL, "%.1f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, /* same as "input.transfer.trim.high" */ { "input.transfer.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageTransfer", NULL, "%.1f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, { "input.transfer.trim.high", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerConverter.Output.HighVoltageBuckTransfer", NULL, "%.1f", HU_FLAG_OK | HU_FLAG_SEMI_STATIC, NULL }, /* Output page */ { "output.voltage", 0, 0, "UPS.PowerConverter.Output.Voltage", NULL, "%.1f", HU_FLAG_OK, NULL }, { "output.current", 0, 0, "UPS.PowerConverter.Output.Current", NULL, "%.2f", HU_FLAG_OK, NULL }, { "output.frequency", 0, 0, "UPS.PowerConverter.Output.Frequency", NULL, "%.1f", HU_FLAG_OK, NULL }, { "output.voltage.nominal", 0, 0, "UPS.PowerSummary.ConfigVoltage", NULL, "%.1f", HU_FLAG_OK, NULL }, /* Outlet page (using MGE UPS SYSTEMS - PowerShare technology) */ /* TODO: add an iterative semantic [%x] to factorise outlets */ { "outlet.0.id", 0, 0, "UPS.OutletSystem.Outlet.[1].OutletID", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_STATIC, NULL }, { "outlet.0.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, "UPS.OutletSystem.Outlet.[1].OutletID", NULL, "Main Outlet", HU_FLAG_ABSENT | HU_FLAG_OK | HU_FLAG_STATIC, NULL }, { "outlet.0.switchable", 0, 0, "UPS.OutletSystem.Outlet.[1].PresentStatus.Switchable", NULL, "%s", HU_FLAG_OK | HU_FLAG_STATIC, &yes_no_info[0] }, { "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet.[2].OutletID", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_STATIC, NULL }, { "outlet.1.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, "UPS.OutletSystem.Outlet.[2].OutletID", NULL, "PowerShare Outlet 1", HU_FLAG_ABSENT | HU_FLAG_OK | HU_FLAG_STATIC, NULL }, { "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet.[2].PresentStatus.Switchable", NULL, "%s", HU_FLAG_OK | HU_FLAG_STATIC, &yes_no_info[0] }, { "outlet.1.status", ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[2].PresentStatus.SwitchOn/Off", NULL, "%s", HU_FLAG_OK, &on_off_info[0] }, /* For low end models, with 1 non backup'ed outlet */ { "outlet.1.status", ST_FLAG_STRING, 3, "UPS.PowerSummary.PresentStatus.ACPresent", NULL, "%s", HU_FLAG_OK, &on_off_info[0] }, { "outlet.1.autoswitch.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[2].RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_OK, NULL }, /* FIXME: use UPS.OutletSystem.Outlet.[x].ShutdownTimer */ { "outlet.1.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[2].ShutdownTimer", NULL, "%.0f", HU_FLAG_OK, NULL }, /* FIXME: use UPS.OutletSystem.Outlet.[x].StartupTimer */ { "outlet.1.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[2].StartupTimer", NULL, "%.0f", HU_FLAG_OK, NULL }, { "outlet.2.id", 0, 0, "UPS.OutletSystem.Outlet.[3].OutletID", NULL, "%.0f", HU_FLAG_OK | HU_FLAG_STATIC, NULL }, { "outlet.2.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, "UPS.OutletSystem.Outlet.[3].OutletID", NULL, "PowerShare Outlet 2", HU_FLAG_ABSENT | HU_FLAG_OK | HU_FLAG_STATIC, NULL }, { "outlet.2.switchable", 0, 0, "UPS.OutletSystem.Outlet.[3].PresentStatus.Switchable", NULL, "%s", HU_FLAG_OK | HU_FLAG_STATIC, &yes_no_info[0] }, { "outlet.2.status", ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[3].PresentStatus.SwitchOn/Off", NULL, "%s", HU_FLAG_OK, &on_off_info[0] }, { "outlet.2.autoswitch.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[3].RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_OK, NULL }, /* FIXME: use UPS.OutletSystem.Outlet.[x].ShutdownTimer */ { "outlet.2.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[3].ShutdownTimer", NULL, "%.0f", HU_FLAG_OK, NULL }, /* FIXME: use UPS.OutletSystem.Outlet.[x].StartupTimer */ { "outlet.2.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[3].StartupTimer", NULL, "%.0f", HU_FLAG_OK, NULL }, /* instant commands. */ /* splited into subset while waiting for extradata support * ie: test.battery.start quick */ { "test.battery.start.quick", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "1", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, &test_write_info[0] }, /* TODO: lookup needed? */ { "test.battery.start.deep", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "2", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, &test_write_info[0] }, { "test.battery.stop", 0, 0, "UPS.BatterySystem.Battery.Test", NULL, "3", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, &test_write_info[0] }, { "load.off", 0, 0, "UPS.PowerSummary.DelayBeforeShutdown", NULL, "0", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, NULL }, { "load.on", 0, 0, "UPS.PowerSummary.DelayBeforeStartup", NULL, "0", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, NULL }, { "beeper.off", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "1", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, NULL }, { "beeper.on", 0, 0, "UPS.PowerSummary.AudibleAlarmControl", NULL, "2", /* point to good value */ HU_TYPE_CMD | HU_FLAG_OK, NULL }, /* FIXME: add beeper.mute , value "3" */ /* Command for the outlet collection */ /* FIXME: not existing in new-names.txt => complete it or use "load.off {all, outletX}" ? */ { "outlet.1.load.off", 0, 0, "UPS.OutletSystem.Outlet.[2].DelayBeforeShutdown", NULL, "0", HU_TYPE_CMD | HU_FLAG_OK, NULL }, { "outlet.1.load.on", 0, 0, "UPS.OutletSystem.Outlet.[2].DelayBeforeStartup", NULL, "0", HU_TYPE_CMD | HU_FLAG_OK, NULL }, { "outlet.2.load.off", 0, 0, "UPS.OutletSystem.Outlet.[3].DelayBeforeShutdown", NULL, "0", HU_TYPE_CMD | HU_FLAG_OK, NULL }, { "outlet.2.load.on", 0, 0, "UPS.OutletSystem.Outlet.[3].DelayBeforeStartup", NULL, "0", HU_TYPE_CMD | HU_FLAG_OK, NULL }, /* TODO: bypass.start/stop, shutdown.return/stayoff/stop/reboot[.graceful] */ /* end of structure. */ { NULL, 0, 0, NULL, NULL, NULL, 0, NULL } }; /* shutdown method for MGE */ static int mge_shutdown(int ondelay, int offdelay) { char delay[7]; /* 1) set DelayBeforeStartup */ sprintf(delay, "%i", ondelay); if (setvar("ups.delay.start", delay) != STAT_SET_HANDLED) { upsdebugx(2, "Shutoff command failed (setting ondelay)"); return 0; } /* 2) set DelayBeforeShutdown */ sprintf(delay, "%i", offdelay); if (setvar("ups.delay.shutdown", delay) == STAT_SET_HANDLED) { return 1; } upsdebugx(2, "Shutoff command failed (setting offdelay)"); return 0; } /* All the logic for finely formatting the MGE model name */ static char *get_model_name(const char *iProduct, char *iModel) { models_name_t *model = NULL; upsdebugx(2, "get_model_name(%s, %s)\n", iProduct, iModel); /* Search for formatting rules */ for ( model = mge_model_names ; model->iProduct != NULL ; model++ ) { upsdebugx(2, "comparing with: %s", model->finalname); /* FIXME: use comp_size if not -1 */ if ( (!strncmp(iProduct, model->iProduct, strlen(model->iProduct))) && (!strncmp(iModel, model->iModel, strlen(model->iModel))) ) { upsdebugx(2, "Found %s\n", model->finalname); break; } } /* FIXME: if we end up with model->iProduct == NULL * then process name in a generic way (not yet supported models!) * Will the following do? */ if (model->iProduct == NULL) { return iModel; } return model->finalname; } static char *mge_format_model(HIDDevice_t *hd) { char *product; char *model; char *string; float appPower; unsigned char rawbuf[100]; /* Get iModel and iProduct strings */ product = hd->Product ? hd->Product : "unknown"; if ((string = HIDGetItemString(udev, "UPS.PowerSummary.iModel", rawbuf, mge_utab)) != NULL) model = get_model_name(product, string); else { /* Try with ConfigApparentPower */ if (HIDGetItemValue(udev, "UPS.Flow.[4].ConfigApparentPower", &appPower, mge_utab) != 0 ) { string = xmalloc(16); sprintf(string, "%i", (int)appPower); model = get_model_name(product, string); free (string); } else model = product; } return model; } static char *mge_format_mfr(HIDDevice_t *hd) { return hd->Vendor ? hd->Vendor : "MGE UPS SYSTEMS"; } static char *mge_format_serial(HIDDevice_t *hd) { return hd->Serial; } /* this function allows the subdriver to "claim" a device: return 1 if * the device is supported by this subdriver, else 0. */ static int mge_claim(HIDDevice_t *hd) { if (hd->VendorID != MGE_VENDORID) { return 0; } switch (hd->ProductID) { case 0x0001: case 0xffff: return 1; /* accept known UPSs */ default: if (getval("productid")) { return 1; } else { upsdebugx(1, "This MGE device (%04x/%04x) is not (or perhaps not yet) supported\n" "by usbhid-ups. Please make sure you have an up-to-date version of NUT. If\n" "this does not fix the problem, try running the driver with the\n" "'-x productid=%04x' option. Please report your results to the NUT user's\n" "mailing list .\n", hd->VendorID, hd->ProductID, hd->ProductID); return 0; } } } subdriver_t mge_subdriver = { MGE_HID_VERSION, mge_claim, mge_utab, mge_hid2nut, mge_shutdown, mge_format_model, mge_format_mfr, mge_format_serial, };