1 /*
2  * mib.cpp
3  *
4  * CI -> OID mapping for SNMP Lite UPS driver
5  */
6 
7 /*
8  * Copyright (C) 2010 Adam Kropelin
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General
12  * Public License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this program; if not, write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1335, USA.
23  */
24 
25 #include "apc.h"
26 #include "snmplite-common.h"
27 #include "mibs.h"
28 #include "rfc1628-oids.h"
29 
30 using namespace Asn;
31 
32 static struct CiOidMap Rfc1628CiOidMap[] =
33 {
34 //  CI                  OID                                type         dynamic?
35    {CI_UPSMODEL,        upsIdentModel,                     OCTETSTRING, false},
36    {CI_IDEN,            upsIdentName,                      OCTETSTRING, false},
37    {CI_REVNO,           upsIdentUPSSoftwareVersion,        OCTETSTRING, false},
38 // {CI_MANDAT,          upsAdvIdentDateOfManufacture,      OCTETSTRING, false},
39 // {CI_BATTDAT,         upsBasicBatteryLastReplaceDate,    OCTETSTRING, false},
40 // {CI_NOMBATTV,        upsAdvBatteryNominalVoltage,       INTEGER,     false},
41    {CI_NOMOUTV,         upsConfigOutputVoltage,            INTEGER,     false},
42    {CI_NOMINV,          upsConfigInputVoltage,             INTEGER,     false},
43    {CI_NOMPOWER,        upsConfigOutputPower,              INTEGER,     false},
44    {CI_LTRANS,          upsConfigLowVoltageTransferPoint,  INTEGER,     false},
45    {CI_HTRANS,          upsConfigHighVoltageTransferPoint, INTEGER,     false},
46 // {CI_DWAKE,           upsAdvConfigReturnDelay,           TIMETICKS,   false},
47    {CI_DALARM,          upsConfigAudibleStatus,            INTEGER,     false},
48    {CI_DLBATT,          upsConfigLowBattTime,              INTEGER,     false},
49 // {CI_DSHUTD,          upsAdvConfigShutoffDelay,          TIMETICKS,   false},
50 // {CI_RETPCT,          upsAdvConfigMinReturnCapacity,     INTEGER,     false},
51 // {CI_SENS,            upsAdvConfigSensitivity,           INTEGER,     false},
52 // {CI_EXTBATTS,        upsAdvBatteryNumOfBattPacks,       INTEGER,     false},
53 // {CI_STESTI,          upsAdvTestDiagnosticSchedule,      INTEGER,     false},
54    {CI_VLINE,           upsInputTableInputVoltage,         SEQUENCE,    true },
55    {CI_VOUT,            upsOutputTableOutputVoltage,       SEQUENCE,    true },
56    {CI_VBATT,           upsBatteryVoltage,                 INTEGER,     true },
57    {CI_FREQ,            upsInputTableInputFrequency,       SEQUENCE,    true },
58    {CI_LOAD,            upsOutputTableOutputPercentLoad,   SEQUENCE,    true },
59    {CI_ITEMP,           upsBatteryTemperature,             INTEGER,     true },
60 // {CI_ATEMP,           mUpsEnvironAmbientTemperature,     GAUGE,       true },
61 // {CI_HUMID,           mUpsEnvironRelativeHumidity,       GAUGE,       true },
62    {CI_ST_STAT,         upsTestResultsSummary,             INTEGER,     true },
63    {CI_BATTLEV,         upsEstimatedChargeRemaining,       INTEGER,     true },
64    {CI_RUNTIM,          upsEstimatedMinutesRemaining,      INTEGER,     true },
65 // {CI_WHY_BATT,        upsAdvInputLineFailCause,          INTEGER,     true },
66 // {CI_BADBATTS,        upsAdvBatteryNumOfBadBattPacks,    INTEGER,     true },
67 // {CI_VMIN,            upsAdvInputMinLineVoltage,         GAUGE,       true },
68 // {CI_VMAX,            upsAdvInputMaxLineVoltage,         GAUGE,       true },
69    {CI_STATUS,          upsOutputSource,                   INTEGER,     true },
70    {CI_LowBattery,      upsBatteryStatus,                  INTEGER,     true },
71 
72    {-1, NULL, false}   /* END OF TABLE */
73 };
74 
rfc1628_update_ci(UPSINFO * ups,int ci,Snmp::Variable & data)75 static void rfc1628_update_ci(UPSINFO *ups, int ci, Snmp::Variable &data)
76 {
77    switch (ci)
78    {
79    case CI_VLINE:
80       // We just take the voltage from the first input line and ignore the rest
81       Dmsg(80, "Got CI_VLINE: %d\n", data.seq.begin()->u32);
82       ups->LineVoltage = data.seq.begin()->u32;
83       break;
84 
85    case CI_VOUT:
86       // We just take the voltage from the first input line and ignore the rest
87       Dmsg(80, "Got CI_VOUT: %d\n", data.seq.begin()->u32);
88       ups->OutputVoltage = data.seq.begin()->u32;
89       break;
90 
91    case CI_VBATT:
92       Dmsg(80, "Got CI_VBATT: %d\n", data.u32);
93       ups->BattVoltage = ((double)data.u32) / 10;
94       break;
95 
96    case CI_FREQ:
97       // We just take the freq from the first input line and ignore the rest
98       Dmsg(80, "Got CI_FREQ: %d\n", data.seq.begin()->u32);
99       ups->LineFreq = ((double)data.seq.begin()->u32) / 10;
100       break;
101 
102    case CI_LOAD:
103       // MIB defines this as "The percentage of the UPS power capacity
104       // presently being used on this output line" so we should be able to
105       // add all these up to get a total load for the UPS as a whole.
106       // HOWEVER, manufacturers seem to actually be returning either the same
107       // value in each slot (APC implementation of RFC1628) or percent of
108       // power the line is capable of (Generex CS121 SNMP/WEB Adapter on a
109       // Newave Conceptpower DPA UPS). So we will average the values and hope
110       // for the best.
111       ups->UPSLoad = 0;
112       for (alist<Snmp::Variable>::iterator iter = data.seq.begin();
113            iter != data.seq.end();
114            ++iter)
115       {
116          Dmsg(80, "Got CI_LOAD: %d\n", iter->u32);
117          ups->UPSLoad += iter->u32;
118       }
119       ups->UPSLoad /= data.seq.size();
120       break;
121 
122    case CI_ITEMP:
123       Dmsg(80, "Got CI_ITEMP: %d\n", data.u32);
124       ups->UPSTemp = data.u32;
125       break;
126 
127    case CI_NOMOUTV:
128       Dmsg(80, "Got CI_NOMOUTV: %d\n", data.u32);
129       ups->NomOutputVoltage = data.u32;
130       break;
131 
132    case CI_NOMINV:
133       Dmsg(80, "Got CI_NOMINV: %d\n", data.u32);
134       ups->NomInputVoltage = data.u32;
135       break;
136 
137    case CI_NOMPOWER:
138       Dmsg(80, "Got CI_NOMPOWER: %d\n", data.u32);
139       ups->NomPower = data.u32;
140       break;
141 
142    case CI_LTRANS:
143       Dmsg(80, "Got CI_LTRANS: %d\n", data.u32);
144       ups->lotrans = data.u32;
145       break;
146 
147    case CI_HTRANS:
148       Dmsg(80, "Got CI_HTRANS: %d\n", data.u32);
149       ups->hitrans = data.u32;
150       break;
151 
152    case CI_ST_STAT:
153       Dmsg(80, "Got CI_ST_STAT: %d\n", data.u32);
154       switch (data.u32)
155       {
156       case 1:  /* Passed */
157          ups->testresult = TEST_PASSED;
158          break;
159       case 2:  /* Warning */
160          ups->testresult = TEST_WARNING;
161          break;
162       case 3:  /* Error */
163          ups->testresult = TEST_FAILED;
164          break;
165       case 5:  /* Test in progress */
166          ups->testresult = TEST_INPROGRESS;
167          break;
168       case 4:  /* Aborted */
169       case 6:  /* No test initiated */
170          ups->testresult = TEST_NONE;
171          break;
172       default:
173          ups->testresult = TEST_UNKNOWN;
174          break;
175       }
176       break;
177 
178    case CI_DALARM:
179       Dmsg(80, "Got CI_DALARM: %d\n", data.u32);
180       switch (data.u32)
181       {
182       case 1: // Disabled ("None")
183          strlcpy(ups->beepstate, "N", sizeof(ups->beepstate));
184          break;
185       case 2: // Enabled (T = 30 seconds...just a guess)
186       case 3: // Muted (but enabled)
187       default:
188          strlcpy(ups->beepstate, "T", sizeof(ups->beepstate));
189          break;
190       }
191       break;
192 
193    case CI_UPSMODEL:
194       Dmsg(80, "Got CI_UPSMODEL: %s\n", data.str.str());
195       strlcpy(ups->upsmodel, data.str, sizeof(ups->upsmodel));
196       break;
197 
198    case CI_BATTLEV:
199       Dmsg(80, "Got CI_BATTLEV: %d\n", data.u32);
200       ups->BattChg = data.u32;
201       break;
202 
203    case CI_RUNTIM:
204       Dmsg(80, "Got CI_RUNTIM: %d\n", data.u32);
205       ups->TimeLeft = data.u32;
206       break;
207 
208    case CI_IDEN:
209       Dmsg(80, "Got CI_IDEN: %s\n", data.str.str());
210       strlcpy(ups->upsname, data.str, sizeof(ups->upsname));
211       break;
212 
213    case CI_STATUS:
214       Dmsg(80, "Got CI_STATUS: %d\n", data.u32);
215       /* Clear the following flags: only one status will be TRUE */
216       ups->clear_online();
217       ups->clear_onbatt();
218       ups->clear_boost();
219       ups->clear_trim();
220       switch (data.u32) {
221       case 3:
222          ups->set_online();
223          break;
224       case 5:
225          ups->set_onbatt();
226          break;
227       case 6:
228          ups->set_online();
229          ups->set_boost();
230          break;
231       case 7:
232          ups->set_online();
233          ups->set_trim();
234          break;
235       case 1:                     /* other */
236       case 2:                     /* output turned off */
237       case 4:                     /* bypass */
238       default:                    /* unknown */
239          break;
240       }
241       break;
242 
243    case CI_LowBattery:
244       Dmsg(80, "Got CI_LowBattery: %d\n", data.u32);
245       switch (data.u32)
246       {
247       default:
248       case 1:  // Unknown
249       case 2:  // Normal
250          ups->clear_battlow();
251          break;
252       case 3:  // Low
253       case 4:  // Depleted
254          ups->set_battlow();
255          break;
256       }
257       break;
258 
259    case CI_REVNO:
260       Dmsg(80, "Got CI_REVNO: %s\n", data.str.str());
261       strlcpy(ups->firmrev, data.str, sizeof(ups->firmrev));
262       break;
263 
264    case CI_DLBATT:
265       Dmsg(80, "Got CI_DLBATT: %d\n", data.u32);
266       ups->dlowbatt = data.u32;
267       break;
268    }
269 }
270 
rfc1628_killpower(Snmp::SnmpEngine * snmp)271 static int rfc1628_killpower(Snmp::SnmpEngine *snmp)
272 {
273    // Configure UPS to turn off output only (not entire UPS)
274    Snmp::Variable shutdownType(Asn::INTEGER, 1);
275    snmp->Set(upsShutdownType, &shutdownType);
276 
277    // Configure UPS to automatically restart when power is restored
278    Snmp::Variable autoRestart(Asn::INTEGER, 1);
279    snmp->Set(upsAutoRestart, &autoRestart);
280 
281    // Instruct UPS to turn off after 60 secs
282    Snmp::Variable shutdownDelay(Asn::INTEGER, 60);
283    snmp->Set(upsShutdownAfterDelay, &shutdownDelay);
284 
285    return 0;
286 }
287 
rfc1628_shutdown(Snmp::SnmpEngine * snmp)288 static int rfc1628_shutdown(Snmp::SnmpEngine *snmp)
289 {
290    // Configure UPS to turn off entire system
291    Snmp::Variable shutdownType(Asn::INTEGER, 2);
292    snmp->Set(upsShutdownType, &shutdownType);
293 
294    // Configure UPS to NOT automatically restart when power is restored
295    Snmp::Variable autoRestart(Asn::INTEGER, 2);
296    snmp->Set(upsAutoRestart, &autoRestart);
297 
298    // Instruct UPS to turn off after 60 secs
299    Snmp::Variable shutdownDelay(Asn::INTEGER, 60);
300    snmp->Set(upsShutdownAfterDelay, &shutdownDelay);
301 
302    return 0;
303 }
304 
305 // Export strategy to snmplite.cpp
306 struct MibStrategy Rfc1628MibStrategy =
307 {
308    "RFC",
309    Rfc1628CiOidMap,
310    rfc1628_update_ci,
311    rfc1628_killpower,
312    rfc1628_shutdown,
313 };
314