Imported Upstream version 2.6.2
This commit is contained in:
parent
a367d9bc54
commit
45043b58d0
246 changed files with 18228 additions and 1415 deletions
|
@ -29,13 +29,16 @@ endif
|
|||
if WITH_LIBPOWERMAN
|
||||
AM_CFLAGS += $(LIBPOWERMAN_CFLAGS)
|
||||
endif
|
||||
if WITH_IPMI
|
||||
AM_CFLAGS += $(LIBIPMI_CFLAGS)
|
||||
endif
|
||||
|
||||
SERIAL_DRIVERLIST = apcsmart bcmxcp belkin belkinunv bestfcom \
|
||||
SERIAL_DRIVERLIST = bcmxcp belkin belkinunv bestfcom \
|
||||
bestfortress bestuferrups bestups dummy-ups etapro everups \
|
||||
gamatronic genericups isbmex liebert liebert-esp2 masterguard metasys \
|
||||
mge-shut mge-utalk microdowell newmge-shut oneac optiups powercom rhino \
|
||||
safenet skel solis tripplite tripplitesu upscode2 victronups powerpanel \
|
||||
blazer_ser clone clone-outlet ivtscd
|
||||
blazer_ser clone clone-outlet ivtscd apcsmart apcsmart-old
|
||||
SNMP_DRIVERLIST = snmp-ups
|
||||
USB_LIBUSB_DRIVERLIST = usbhid-ups bcmxcp_usb tripplite_usb \
|
||||
blazer_usb richcomm_usb
|
||||
|
@ -71,6 +74,9 @@ endif
|
|||
if WITH_LIBPOWERMAN
|
||||
driverexec_PROGRAMS += powerman-pdu
|
||||
endif
|
||||
if WITH_IPMI
|
||||
driverexec_PROGRAMS += nut-ipmipsu
|
||||
endif
|
||||
else
|
||||
driverexec_PROGRAMS += skel
|
||||
endif
|
||||
|
@ -86,7 +92,8 @@ upsdrvctl_SOURCES = upsdrvctl.c
|
|||
upsdrvctl_LDADD = $(LDADD_COMMON)
|
||||
|
||||
# serial drivers: all of them use standard LDADD and CFLAGS
|
||||
apcsmart_SOURCES = apcsmart.c
|
||||
apcsmart_SOURCES = apcsmart.c apcsmart_tabs.c
|
||||
apcsmart_old_SOURCES = apcsmart-old.c
|
||||
bcmxcp_SOURCES = bcmxcp.c bcmxcp_ser.c
|
||||
bcmxcp_LDADD = $(LDADD) -lm
|
||||
belkin_SOURCES = belkin.c
|
||||
|
@ -200,20 +207,28 @@ netxml_ups_LDADD = $(LDADD_DRIVERS) $(LIBNEON_LIBS)
|
|||
powerman_pdu_SOURCES = powerman-pdu.c
|
||||
powerman_pdu_LDADD = $(LDADD) $(LIBPOWERMAN_LIBS)
|
||||
|
||||
# IPMI PSU
|
||||
nut_ipmipsu_SOURCES = nut-ipmipsu.c
|
||||
if WITH_FREEIPMI
|
||||
nut_ipmipsu_SOURCES += nut-libfreeipmi.c
|
||||
endif
|
||||
nut_ipmipsu_LDADD = $(LDADD) $(LIBIPMI_LIBS)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# List of header files. The purpose of this list is not dependency
|
||||
# tracking (which is automatic), but to ensure these files are
|
||||
# distributed by "make dist".
|
||||
|
||||
dist_noinst_HEADERS = apc-mib.h apc-hid.h apcsmart.h baytech-mib.h bcmxcp.h \
|
||||
dist_noinst_HEADERS = apc-mib.h apc-hid.h baytech-mib.h bcmxcp.h \
|
||||
bcmxcp_io.h belkin.h belkin-hid.h bestpower-mib.h blazer.h cps-hid.h dstate.h \
|
||||
dstate-hal.h dummy-ups.h eaton-mib.h explore-hid.h gamatronic.h genericups.h \
|
||||
hidparser.h hidtypes.h ietf-mib.h libhid.h libshut.h libusb.h liebert-hid.h \
|
||||
main.h main-hal.h mge-hid.h mge-mib.h mge-shut.h mge-utalk.h \
|
||||
mge-xml.h microdowell.h netvision-mib.h netxml-ups.h oneac.h \
|
||||
mge-xml.h microdowell.h netvision-mib.h netxml-ups.h nut-ipmi.h oneac.h \
|
||||
powercom.h powerpanel.h powerp-bin.h powerp-txt.h powerware-mib.h raritan-pdu-mib.h \
|
||||
safenet.h serial.h snmp-ups.h solis.h tripplite.h tripplite-hid.h \
|
||||
upshandler.h usb-common.h usbhid-ups.h powercom-hid.h compaq-mib.h idowell-hid.h
|
||||
upshandler.h usb-common.h usbhid-ups.h powercom-hid.h compaq-mib.h idowell-hid.h \
|
||||
apcsmart.h apcsmart_tabs.h apcsmart-old.h
|
||||
|
||||
# Define a dummy library so that Automake builds rules for the
|
||||
# corresponding object files. This library is not actually built,
|
||||
|
|
|
@ -43,26 +43,29 @@ target_triplet = @target@
|
|||
@WITH_SNMP_TRUE@am__append_3 = $(LIBNETSNMP_CFLAGS)
|
||||
@WITH_NEONXML_TRUE@am__append_4 = $(LIBNEON_CFLAGS)
|
||||
@WITH_LIBPOWERMAN_TRUE@am__append_5 = $(LIBPOWERMAN_CFLAGS)
|
||||
@WITH_IPMI_TRUE@am__append_6 = $(LIBIPMI_CFLAGS)
|
||||
EXTRA_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_4) \
|
||||
$(am__EXEEXT_5)
|
||||
@SOME_DRIVERS_FALSE@driverexec_PROGRAMS = $(am__EXEEXT_6) \
|
||||
@SOME_DRIVERS_FALSE@ $(am__EXEEXT_7) $(am__EXEEXT_8) \
|
||||
@SOME_DRIVERS_FALSE@ $(am__EXEEXT_9) $(am__EXEEXT_10) \
|
||||
@SOME_DRIVERS_FALSE@ upsdrvctl$(EXEEXT)
|
||||
@SOME_DRIVERS_FALSE@ $(am__EXEEXT_11) upsdrvctl$(EXEEXT)
|
||||
@SOME_DRIVERS_TRUE@driverexec_PROGRAMS = $(DRIVER_BUILD_LIST) \
|
||||
@SOME_DRIVERS_TRUE@ $(am__EXEEXT_6) $(am__EXEEXT_7) \
|
||||
@SOME_DRIVERS_TRUE@ $(am__EXEEXT_8) $(am__EXEEXT_9) \
|
||||
@SOME_DRIVERS_TRUE@ $(am__EXEEXT_10) skel$(EXEEXT) \
|
||||
@SOME_DRIVERS_TRUE@ upsdrvctl$(EXEEXT)
|
||||
@SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@am__append_6 = $(SERIAL_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_SNMP_TRUE@am__append_7 = $(SNMP_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_USB_TRUE@am__append_8 = $(USB_LIBUSB_DRIVERLIST)
|
||||
@SOME_DRIVERS_TRUE@ $(am__EXEEXT_10) $(am__EXEEXT_11) \
|
||||
@SOME_DRIVERS_TRUE@ skel$(EXEEXT) upsdrvctl$(EXEEXT)
|
||||
@SOME_DRIVERS_FALSE@@WITH_SERIAL_TRUE@am__append_7 = $(SERIAL_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_SNMP_TRUE@am__append_8 = $(SNMP_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_USB_TRUE@am__append_9 = $(USB_LIBUSB_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_HAL_TRUE@halexec_PROGRAMS = \
|
||||
@SOME_DRIVERS_FALSE@@WITH_HAL_TRUE@ $(am__EXEEXT_11)
|
||||
@SOME_DRIVERS_FALSE@@WITH_NEONXML_TRUE@am__append_9 = $(NEONXML_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@am__append_10 = powerman-pdu
|
||||
@WITH_SSL_TRUE@am__append_11 = $(LIBSSL_CFLAGS)
|
||||
@WITH_SSL_TRUE@am__append_12 = $(LIBSSL_LIBS)
|
||||
@SOME_DRIVERS_FALSE@@WITH_HAL_TRUE@ $(am__EXEEXT_12)
|
||||
@SOME_DRIVERS_FALSE@@WITH_NEONXML_TRUE@am__append_10 = $(NEONXML_DRIVERLIST)
|
||||
@SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@am__append_11 = powerman-pdu
|
||||
@SOME_DRIVERS_FALSE@@WITH_IPMI_TRUE@am__append_12 = nut-ipmipsu
|
||||
@WITH_SSL_TRUE@am__append_13 = $(LIBSSL_CFLAGS)
|
||||
@WITH_SSL_TRUE@am__append_14 = $(LIBSSL_LIBS)
|
||||
@WITH_FREEIPMI_TRUE@am__append_15 = nut-libfreeipmi.c
|
||||
subdir = drivers
|
||||
DIST_COMMON = $(dist_noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/Makefile.in
|
||||
|
@ -73,6 +76,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
|
|||
$(top_srcdir)/m4/lt~obsolete.m4 \
|
||||
$(top_srcdir)/m4/nut_arg_with.m4 \
|
||||
$(top_srcdir)/m4/nut_check_asciidoc.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libavahi.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libfreeipmi.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libgd.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libhal.m4 \
|
||||
$(top_srcdir)/m4/nut_check_libneon.m4 \
|
||||
|
@ -103,19 +108,19 @@ libnuthalmain_a_LIBADD =
|
|||
am_libnuthalmain_a_OBJECTS = main-hal.$(OBJEXT) dstate-hal.$(OBJEXT) \
|
||||
usb-common.$(OBJEXT)
|
||||
libnuthalmain_a_OBJECTS = $(am_libnuthalmain_a_OBJECTS)
|
||||
am__EXEEXT_1 = apcsmart$(EXEEXT) bcmxcp$(EXEEXT) belkin$(EXEEXT) \
|
||||
belkinunv$(EXEEXT) bestfcom$(EXEEXT) bestfortress$(EXEEXT) \
|
||||
bestuferrups$(EXEEXT) bestups$(EXEEXT) dummy-ups$(EXEEXT) \
|
||||
etapro$(EXEEXT) everups$(EXEEXT) gamatronic$(EXEEXT) \
|
||||
genericups$(EXEEXT) isbmex$(EXEEXT) liebert$(EXEEXT) \
|
||||
liebert-esp2$(EXEEXT) masterguard$(EXEEXT) metasys$(EXEEXT) \
|
||||
mge-shut$(EXEEXT) mge-utalk$(EXEEXT) microdowell$(EXEEXT) \
|
||||
newmge-shut$(EXEEXT) oneac$(EXEEXT) optiups$(EXEEXT) \
|
||||
powercom$(EXEEXT) rhino$(EXEEXT) safenet$(EXEEXT) \
|
||||
skel$(EXEEXT) solis$(EXEEXT) tripplite$(EXEEXT) \
|
||||
tripplitesu$(EXEEXT) upscode2$(EXEEXT) victronups$(EXEEXT) \
|
||||
powerpanel$(EXEEXT) blazer_ser$(EXEEXT) clone$(EXEEXT) \
|
||||
clone-outlet$(EXEEXT) ivtscd$(EXEEXT)
|
||||
am__EXEEXT_1 = bcmxcp$(EXEEXT) belkin$(EXEEXT) belkinunv$(EXEEXT) \
|
||||
bestfcom$(EXEEXT) bestfortress$(EXEEXT) bestuferrups$(EXEEXT) \
|
||||
bestups$(EXEEXT) dummy-ups$(EXEEXT) etapro$(EXEEXT) \
|
||||
everups$(EXEEXT) gamatronic$(EXEEXT) genericups$(EXEEXT) \
|
||||
isbmex$(EXEEXT) liebert$(EXEEXT) liebert-esp2$(EXEEXT) \
|
||||
masterguard$(EXEEXT) metasys$(EXEEXT) mge-shut$(EXEEXT) \
|
||||
mge-utalk$(EXEEXT) microdowell$(EXEEXT) newmge-shut$(EXEEXT) \
|
||||
oneac$(EXEEXT) optiups$(EXEEXT) powercom$(EXEEXT) \
|
||||
rhino$(EXEEXT) safenet$(EXEEXT) skel$(EXEEXT) solis$(EXEEXT) \
|
||||
tripplite$(EXEEXT) tripplitesu$(EXEEXT) upscode2$(EXEEXT) \
|
||||
victronups$(EXEEXT) powerpanel$(EXEEXT) blazer_ser$(EXEEXT) \
|
||||
clone$(EXEEXT) clone-outlet$(EXEEXT) ivtscd$(EXEEXT) \
|
||||
apcsmart$(EXEEXT) apcsmart-old$(EXEEXT)
|
||||
am__EXEEXT_2 = snmp-ups$(EXEEXT)
|
||||
am__EXEEXT_3 = usbhid-ups$(EXEEXT) bcmxcp_usb$(EXEEXT) \
|
||||
tripplite_usb$(EXEEXT) blazer_usb$(EXEEXT) \
|
||||
|
@ -127,19 +132,25 @@ am__EXEEXT_5 = netxml-ups$(EXEEXT)
|
|||
@SOME_DRIVERS_FALSE@@WITH_USB_TRUE@am__EXEEXT_8 = $(am__EXEEXT_3)
|
||||
@SOME_DRIVERS_FALSE@@WITH_NEONXML_TRUE@am__EXEEXT_9 = $(am__EXEEXT_5)
|
||||
@SOME_DRIVERS_FALSE@@WITH_LIBPOWERMAN_TRUE@am__EXEEXT_10 = powerman-pdu$(EXEEXT)
|
||||
@SOME_DRIVERS_FALSE@@WITH_IPMI_TRUE@am__EXEEXT_11 = \
|
||||
@SOME_DRIVERS_FALSE@@WITH_IPMI_TRUE@ nut-ipmipsu$(EXEEXT)
|
||||
am__installdirs = "$(DESTDIR)$(driverexecdir)" \
|
||||
"$(DESTDIR)$(halexecdir)"
|
||||
am__EXEEXT_11 = hald-addon-usbhid-ups$(EXEEXT) \
|
||||
am__EXEEXT_12 = hald-addon-usbhid-ups$(EXEEXT) \
|
||||
hald-addon-bcmxcp_usb$(EXEEXT) \
|
||||
hald-addon-tripplite_usb$(EXEEXT) \
|
||||
hald-addon-blazer_usb$(EXEEXT)
|
||||
PROGRAMS = $(driverexec_PROGRAMS) $(halexec_PROGRAMS)
|
||||
am_apcsmart_OBJECTS = apcsmart.$(OBJEXT)
|
||||
am_apcsmart_OBJECTS = apcsmart.$(OBJEXT) apcsmart_tabs.$(OBJEXT)
|
||||
apcsmart_OBJECTS = $(am_apcsmart_OBJECTS)
|
||||
apcsmart_LDADD = $(LDADD)
|
||||
am__DEPENDENCIES_1 =
|
||||
am__DEPENDENCIES_2 = $(LDADD_DRIVERS) $(am__DEPENDENCIES_1) serial.o
|
||||
apcsmart_DEPENDENCIES = $(am__DEPENDENCIES_2)
|
||||
am_apcsmart_old_OBJECTS = apcsmart-old.$(OBJEXT)
|
||||
apcsmart_old_OBJECTS = $(am_apcsmart_old_OBJECTS)
|
||||
apcsmart_old_LDADD = $(LDADD)
|
||||
apcsmart_old_DEPENDENCIES = $(am__DEPENDENCIES_2)
|
||||
am_bcmxcp_OBJECTS = bcmxcp.$(OBJEXT) bcmxcp_ser.$(OBJEXT)
|
||||
bcmxcp_OBJECTS = $(am_bcmxcp_OBJECTS)
|
||||
am__DEPENDENCIES_3 = $(am__DEPENDENCIES_2)
|
||||
|
@ -283,6 +294,11 @@ newmge_shut_DEPENDENCIES = $(am__DEPENDENCIES_3)
|
|||
newmge_shut_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(newmge_shut_CFLAGS) \
|
||||
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
am__nut_ipmipsu_SOURCES_DIST = nut-ipmipsu.c nut-libfreeipmi.c
|
||||
@WITH_FREEIPMI_TRUE@am__objects_2 = nut-libfreeipmi.$(OBJEXT)
|
||||
am_nut_ipmipsu_OBJECTS = nut-ipmipsu.$(OBJEXT) $(am__objects_2)
|
||||
nut_ipmipsu_OBJECTS = $(am_nut_ipmipsu_OBJECTS)
|
||||
nut_ipmipsu_DEPENDENCIES = $(am__DEPENDENCIES_3) $(am__DEPENDENCIES_1)
|
||||
am_oneac_OBJECTS = oneac.$(OBJEXT)
|
||||
oneac_OBJECTS = $(am_oneac_OBJECTS)
|
||||
oneac_LDADD = $(LDADD)
|
||||
|
@ -366,21 +382,22 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
|
|||
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
|
||||
$(LDFLAGS) -o $@
|
||||
SOURCES = $(libdummy_a_SOURCES) $(libnuthalmain_a_SOURCES) \
|
||||
$(apcsmart_SOURCES) $(bcmxcp_SOURCES) $(bcmxcp_usb_SOURCES) \
|
||||
$(belkin_SOURCES) $(belkinunv_SOURCES) $(bestfcom_SOURCES) \
|
||||
bestfortress.c $(bestuferrups_SOURCES) $(bestups_SOURCES) \
|
||||
$(blazer_ser_SOURCES) $(blazer_usb_SOURCES) $(clone_SOURCES) \
|
||||
$(clone_outlet_SOURCES) $(dummy_ups_SOURCES) $(etapro_SOURCES) \
|
||||
$(everups_SOURCES) $(gamatronic_SOURCES) $(genericups_SOURCES) \
|
||||
$(hald_addon_bcmxcp_usb_SOURCES) \
|
||||
$(apcsmart_SOURCES) $(apcsmart_old_SOURCES) $(bcmxcp_SOURCES) \
|
||||
$(bcmxcp_usb_SOURCES) $(belkin_SOURCES) $(belkinunv_SOURCES) \
|
||||
$(bestfcom_SOURCES) bestfortress.c $(bestuferrups_SOURCES) \
|
||||
$(bestups_SOURCES) $(blazer_ser_SOURCES) $(blazer_usb_SOURCES) \
|
||||
$(clone_SOURCES) $(clone_outlet_SOURCES) $(dummy_ups_SOURCES) \
|
||||
$(etapro_SOURCES) $(everups_SOURCES) $(gamatronic_SOURCES) \
|
||||
$(genericups_SOURCES) $(hald_addon_bcmxcp_usb_SOURCES) \
|
||||
$(hald_addon_blazer_usb_SOURCES) \
|
||||
$(hald_addon_tripplite_usb_SOURCES) \
|
||||
$(hald_addon_usbhid_ups_SOURCES) $(isbmex_SOURCES) \
|
||||
$(ivtscd_SOURCES) $(liebert_SOURCES) $(liebert_esp2_SOURCES) \
|
||||
$(masterguard_SOURCES) $(metasys_SOURCES) $(mge_shut_SOURCES) \
|
||||
$(mge_utalk_SOURCES) $(microdowell_SOURCES) \
|
||||
$(netxml_ups_SOURCES) $(newmge_shut_SOURCES) $(oneac_SOURCES) \
|
||||
$(optiups_SOURCES) $(powercom_SOURCES) $(powerman_pdu_SOURCES) \
|
||||
$(netxml_ups_SOURCES) $(newmge_shut_SOURCES) \
|
||||
$(nut_ipmipsu_SOURCES) $(oneac_SOURCES) $(optiups_SOURCES) \
|
||||
$(powercom_SOURCES) $(powerman_pdu_SOURCES) \
|
||||
$(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \
|
||||
$(safenet_SOURCES) $(skel_SOURCES) $(snmp_ups_SOURCES) \
|
||||
$(solis_SOURCES) $(tripplite_SOURCES) $(tripplite_usb_SOURCES) \
|
||||
|
@ -388,20 +405,21 @@ SOURCES = $(libdummy_a_SOURCES) $(libnuthalmain_a_SOURCES) \
|
|||
$(upsdrvctl_SOURCES) $(usbhid_ups_SOURCES) \
|
||||
$(victronups_SOURCES)
|
||||
DIST_SOURCES = $(libdummy_a_SOURCES) $(libnuthalmain_a_SOURCES) \
|
||||
$(apcsmart_SOURCES) $(bcmxcp_SOURCES) $(bcmxcp_usb_SOURCES) \
|
||||
$(belkin_SOURCES) $(belkinunv_SOURCES) $(bestfcom_SOURCES) \
|
||||
bestfortress.c $(bestuferrups_SOURCES) $(bestups_SOURCES) \
|
||||
$(blazer_ser_SOURCES) $(blazer_usb_SOURCES) $(clone_SOURCES) \
|
||||
$(clone_outlet_SOURCES) $(dummy_ups_SOURCES) $(etapro_SOURCES) \
|
||||
$(everups_SOURCES) $(gamatronic_SOURCES) $(genericups_SOURCES) \
|
||||
$(hald_addon_bcmxcp_usb_SOURCES) \
|
||||
$(apcsmart_SOURCES) $(apcsmart_old_SOURCES) $(bcmxcp_SOURCES) \
|
||||
$(bcmxcp_usb_SOURCES) $(belkin_SOURCES) $(belkinunv_SOURCES) \
|
||||
$(bestfcom_SOURCES) bestfortress.c $(bestuferrups_SOURCES) \
|
||||
$(bestups_SOURCES) $(blazer_ser_SOURCES) $(blazer_usb_SOURCES) \
|
||||
$(clone_SOURCES) $(clone_outlet_SOURCES) $(dummy_ups_SOURCES) \
|
||||
$(etapro_SOURCES) $(everups_SOURCES) $(gamatronic_SOURCES) \
|
||||
$(genericups_SOURCES) $(hald_addon_bcmxcp_usb_SOURCES) \
|
||||
$(hald_addon_blazer_usb_SOURCES) \
|
||||
$(hald_addon_tripplite_usb_SOURCES) \
|
||||
$(hald_addon_usbhid_ups_SOURCES) $(isbmex_SOURCES) \
|
||||
$(ivtscd_SOURCES) $(liebert_SOURCES) $(liebert_esp2_SOURCES) \
|
||||
$(masterguard_SOURCES) $(metasys_SOURCES) $(mge_shut_SOURCES) \
|
||||
$(mge_utalk_SOURCES) $(microdowell_SOURCES) \
|
||||
$(netxml_ups_SOURCES) $(newmge_shut_SOURCES) $(oneac_SOURCES) \
|
||||
$(netxml_ups_SOURCES) $(newmge_shut_SOURCES) \
|
||||
$(am__nut_ipmipsu_SOURCES_DIST) $(oneac_SOURCES) \
|
||||
$(optiups_SOURCES) $(powercom_SOURCES) $(powerman_pdu_SOURCES) \
|
||||
$(powerpanel_SOURCES) $(rhino_SOURCES) $(richcomm_usb_SOURCES) \
|
||||
$(safenet_SOURCES) $(skel_SOURCES) $(snmp_ups_SOURCES) \
|
||||
|
@ -457,10 +475,14 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
|||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBAVAHI_CFLAGS = @LIBAVAHI_CFLAGS@
|
||||
LIBAVAHI_LIBS = @LIBAVAHI_LIBS@
|
||||
LIBGD_CFLAGS = @LIBGD_CFLAGS@
|
||||
LIBGD_LDFLAGS = @LIBGD_LDFLAGS@
|
||||
LIBHAL_CFLAGS = @LIBHAL_CFLAGS@
|
||||
LIBHAL_LIBS = @LIBHAL_LIBS@
|
||||
LIBIPMI_CFLAGS = @LIBIPMI_CFLAGS@
|
||||
LIBIPMI_LIBS = @LIBIPMI_LIBS@
|
||||
LIBNEON_CFLAGS = @LIBNEON_CFLAGS@
|
||||
LIBNEON_LIBS = @LIBNEON_LIBS@
|
||||
LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@
|
||||
|
@ -498,6 +520,10 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
|||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PORT = @PORT@
|
||||
RANLIB = @RANLIB@
|
||||
RUN_AS_GROUP = @RUN_AS_GROUP@
|
||||
RUN_AS_USER = @RUN_AS_USER@
|
||||
|
@ -562,6 +588,8 @@ sbindir = @sbindir@
|
|||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
systemdsystemshutdowndir = @systemdsystemshutdowndir@
|
||||
systemdsystemunitdir = @systemdsystemunitdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
|
@ -586,13 +614,14 @@ LDADD = $(LDADD_DRIVERS_SERIAL)
|
|||
# files. In any case, CFLAGS are only -I options, so there is no harm,
|
||||
# but only add them if we really use the target.
|
||||
AM_CFLAGS = -I$(top_srcdir)/include $(am__append_1) $(am__append_2) \
|
||||
$(am__append_3) $(am__append_4) $(am__append_5)
|
||||
SERIAL_DRIVERLIST = apcsmart bcmxcp belkin belkinunv bestfcom \
|
||||
$(am__append_3) $(am__append_4) $(am__append_5) \
|
||||
$(am__append_6)
|
||||
SERIAL_DRIVERLIST = bcmxcp belkin belkinunv bestfcom \
|
||||
bestfortress bestuferrups bestups dummy-ups etapro everups \
|
||||
gamatronic genericups isbmex liebert liebert-esp2 masterguard metasys \
|
||||
mge-shut mge-utalk microdowell newmge-shut oneac optiups powercom rhino \
|
||||
safenet skel solis tripplite tripplitesu upscode2 victronups powerpanel \
|
||||
blazer_ser clone clone-outlet ivtscd
|
||||
blazer_ser clone clone-outlet ivtscd apcsmart apcsmart-old
|
||||
|
||||
SNMP_DRIVERLIST = snmp-ups
|
||||
USB_LIBUSB_DRIVERLIST = usbhid-ups bcmxcp_usb tripplite_usb \
|
||||
|
@ -613,7 +642,8 @@ upsdrvctl_SOURCES = upsdrvctl.c
|
|||
upsdrvctl_LDADD = $(LDADD_COMMON)
|
||||
|
||||
# serial drivers: all of them use standard LDADD and CFLAGS
|
||||
apcsmart_SOURCES = apcsmart.c
|
||||
apcsmart_SOURCES = apcsmart.c apcsmart_tabs.c
|
||||
apcsmart_old_SOURCES = apcsmart-old.c
|
||||
bcmxcp_SOURCES = bcmxcp.c bcmxcp_ser.c
|
||||
bcmxcp_LDADD = $(LDADD) -lm
|
||||
belkin_SOURCES = belkin.c
|
||||
|
@ -659,9 +689,9 @@ victronups_SOURCES = victronups.c
|
|||
# dummy
|
||||
dummy_ups_SOURCES = dummy-ups.c
|
||||
dummy_ups_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/clients \
|
||||
$(am__append_11)
|
||||
$(am__append_13)
|
||||
dummy_ups_LDADD = $(LDADD_DRIVERS) ../clients/libupsclient.la \
|
||||
$(am__append_12)
|
||||
$(am__append_14)
|
||||
|
||||
# Clone drivers
|
||||
clone_SOURCES = clone.c
|
||||
|
@ -721,19 +751,24 @@ netxml_ups_LDADD = $(LDADD_DRIVERS) $(LIBNEON_LIBS)
|
|||
powerman_pdu_SOURCES = powerman-pdu.c
|
||||
powerman_pdu_LDADD = $(LDADD) $(LIBPOWERMAN_LIBS)
|
||||
|
||||
# IPMI PSU
|
||||
nut_ipmipsu_SOURCES = nut-ipmipsu.c $(am__append_15)
|
||||
nut_ipmipsu_LDADD = $(LDADD) $(LIBIPMI_LIBS)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# List of header files. The purpose of this list is not dependency
|
||||
# tracking (which is automatic), but to ensure these files are
|
||||
# distributed by "make dist".
|
||||
dist_noinst_HEADERS = apc-mib.h apc-hid.h apcsmart.h baytech-mib.h bcmxcp.h \
|
||||
dist_noinst_HEADERS = apc-mib.h apc-hid.h baytech-mib.h bcmxcp.h \
|
||||
bcmxcp_io.h belkin.h belkin-hid.h bestpower-mib.h blazer.h cps-hid.h dstate.h \
|
||||
dstate-hal.h dummy-ups.h eaton-mib.h explore-hid.h gamatronic.h genericups.h \
|
||||
hidparser.h hidtypes.h ietf-mib.h libhid.h libshut.h libusb.h liebert-hid.h \
|
||||
main.h main-hal.h mge-hid.h mge-mib.h mge-shut.h mge-utalk.h \
|
||||
mge-xml.h microdowell.h netvision-mib.h netxml-ups.h oneac.h \
|
||||
mge-xml.h microdowell.h netvision-mib.h netxml-ups.h nut-ipmi.h oneac.h \
|
||||
powercom.h powerpanel.h powerp-bin.h powerp-txt.h powerware-mib.h raritan-pdu-mib.h \
|
||||
safenet.h serial.h snmp-ups.h solis.h tripplite.h tripplite-hid.h \
|
||||
upshandler.h usb-common.h usbhid-ups.h powercom-hid.h compaq-mib.h idowell-hid.h
|
||||
upshandler.h usb-common.h usbhid-ups.h powercom-hid.h compaq-mib.h idowell-hid.h \
|
||||
apcsmart.h apcsmart_tabs.h apcsmart-old.h
|
||||
|
||||
|
||||
# Define a dummy library so that Automake builds rules for the
|
||||
|
@ -879,6 +914,9 @@ clean-halexecPROGRAMS:
|
|||
apcsmart$(EXEEXT): $(apcsmart_OBJECTS) $(apcsmart_DEPENDENCIES)
|
||||
@rm -f apcsmart$(EXEEXT)
|
||||
$(LINK) $(apcsmart_OBJECTS) $(apcsmart_LDADD) $(LIBS)
|
||||
apcsmart-old$(EXEEXT): $(apcsmart_old_OBJECTS) $(apcsmart_old_DEPENDENCIES)
|
||||
@rm -f apcsmart-old$(EXEEXT)
|
||||
$(LINK) $(apcsmart_old_OBJECTS) $(apcsmart_old_LDADD) $(LIBS)
|
||||
bcmxcp$(EXEEXT): $(bcmxcp_OBJECTS) $(bcmxcp_DEPENDENCIES)
|
||||
@rm -f bcmxcp$(EXEEXT)
|
||||
$(LINK) $(bcmxcp_OBJECTS) $(bcmxcp_LDADD) $(LIBS)
|
||||
|
@ -975,6 +1013,9 @@ netxml-ups$(EXEEXT): $(netxml_ups_OBJECTS) $(netxml_ups_DEPENDENCIES)
|
|||
newmge-shut$(EXEEXT): $(newmge_shut_OBJECTS) $(newmge_shut_DEPENDENCIES)
|
||||
@rm -f newmge-shut$(EXEEXT)
|
||||
$(newmge_shut_LINK) $(newmge_shut_OBJECTS) $(newmge_shut_LDADD) $(LIBS)
|
||||
nut-ipmipsu$(EXEEXT): $(nut_ipmipsu_OBJECTS) $(nut_ipmipsu_DEPENDENCIES)
|
||||
@rm -f nut-ipmipsu$(EXEEXT)
|
||||
$(LINK) $(nut_ipmipsu_OBJECTS) $(nut_ipmipsu_LDADD) $(LIBS)
|
||||
oneac$(EXEEXT): $(oneac_OBJECTS) $(oneac_DEPENDENCIES)
|
||||
@rm -f oneac$(EXEEXT)
|
||||
$(LINK) $(oneac_OBJECTS) $(oneac_LDADD) $(LIBS)
|
||||
|
@ -1038,7 +1079,9 @@ distclean-compile:
|
|||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apc-hid.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apc-mib.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcsmart-old.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcsmart.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apcsmart_tabs.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/baytech-mib.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bcmxcp.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bcmxcp_ser.Po@am__quote@
|
||||
|
@ -1094,6 +1137,8 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newmge_shut-libshut.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newmge_shut-mge-hid.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/newmge_shut-usbhid-ups.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nut-ipmipsu.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nut-libfreeipmi.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oneac.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/optiups.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powercom-hid.Po@am__quote@
|
||||
|
|
|
@ -27,6 +27,17 @@
|
|||
|
||||
#define APCC_MIB_VERSION "1.1"
|
||||
|
||||
/* Other APC sysOID:
|
||||
*
|
||||
* examples found on the Net and other sources:
|
||||
* 'enterprises.apc.products.system.smartUPS.smartUPS700'
|
||||
* '.1.3.6.1.4.1.318.1.3.4.5': ApcRPDU,
|
||||
* '.1.3.6.1.4.1.318.1.3.4.4': ApcMSP
|
||||
*/
|
||||
|
||||
/* TODO: find the right sysOID for this MIB
|
||||
* Ie ".1.3.6.1.4.1.318.1.1.1" or ".1.3.6.1.4.1.318" or? */
|
||||
|
||||
/* info elements */
|
||||
|
||||
#define APCC_OID_BATT_STATUS ".1.3.6.1.4.1.318.1.1.1.2.1.1.0"
|
||||
|
|
1501
drivers/apcsmart-old.c
Normal file
1501
drivers/apcsmart-old.c
Normal file
File diff suppressed because it is too large
Load diff
291
drivers/apcsmart-old.h
Normal file
291
drivers/apcsmart-old.h
Normal file
|
@ -0,0 +1,291 @@
|
|||
/* apcsmart.h - command table for APC smart protocol units
|
||||
|
||||
Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
|
||||
(C) 2000 Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>
|
||||
|
||||
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 <ctype.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "serial.h"
|
||||
#include "timehead.h"
|
||||
|
||||
#define APC_TABLE_VERSION "version 2.2"
|
||||
|
||||
/* Basic UPS reply line structure */
|
||||
#define ENDCHAR 10 /* APC ends responses with LF */
|
||||
|
||||
/* characters ignored by default */
|
||||
#define IGNCHARS "\015+$|!~%?=#&" /* special characters to ignore */
|
||||
|
||||
/* these one is used only during startup, due to ^Z sending certain characters such as # */
|
||||
#define MINIGNCHARS "\015+$|!" /* minimum set of special characters to ignore */
|
||||
|
||||
/* normal polls: characters we don't want to parse (including a few alerts) */
|
||||
#define POLL_IGNORE "\015&|"
|
||||
|
||||
/* alert characters we care about - OL, OB, LB, not LB, RB, OVER, not OVER */
|
||||
#define POLL_ALERT "$!%+#?="
|
||||
|
||||
#define UPSDELAY 50000 /* slow down multicharacter commands */
|
||||
#define CMDLONGDELAY 1500000 /* some commands need a 1.5s gap for safety */
|
||||
|
||||
#define SER_WAIT_SEC 3 /* wait up to 3.0 sec for ser_get calls */
|
||||
#define SER_WAIT_USEC 0
|
||||
|
||||
/* dangerous instant commands must be reconfirmed within a 12 second window */
|
||||
#define MINCMDTIME 3
|
||||
#define MAXCMDTIME 15
|
||||
|
||||
/* it only does two strings, and they're both the same length */
|
||||
#define APC_STRLEN 8
|
||||
|
||||
/* --------------- */
|
||||
|
||||
/* status bits */
|
||||
|
||||
#define APC_STAT_CAL 1 /* calibration */
|
||||
#define APC_STAT_TRIM 2 /* SmartTrim */
|
||||
#define APC_STAT_BOOST 4 /* SmartBoost */
|
||||
#define APC_STAT_OL 8 /* on line */
|
||||
#define APC_STAT_OB 16 /* on battery */
|
||||
#define APC_STAT_OVER 32 /* overload */
|
||||
#define APC_STAT_LB 64 /* low battery */
|
||||
#define APC_STAT_RB 128 /* replace battery */
|
||||
|
||||
/* serial protocol: special commands - initialization and such */
|
||||
#define APC_STATUS 'Q'
|
||||
#define APC_GOSMART 'Y'
|
||||
#define APC_GODUMB 'R'
|
||||
#define APC_CMDSET 'a'
|
||||
#define APC_CAPABILITY 26 /* ^Z */
|
||||
#define APC_NEXTVAL '-'
|
||||
|
||||
/* --------------- */
|
||||
|
||||
/* Driver command table flag values */
|
||||
|
||||
#define APC_POLL 0x0001 /* Poll this variable regularly */
|
||||
#define APC_PRESENT 0x0004 /* Capability seen on this UPS */
|
||||
|
||||
#define APC_RW 0x0010 /* read-write variable */
|
||||
#define APC_ENUM 0x0020 /* enumerated type */
|
||||
#define APC_STRING 0x0040 /* string */
|
||||
|
||||
#define APC_NASTY 0x0100 /* Nasty command - take care */
|
||||
#define APC_REPEAT 0x0200 /* Command needs sending twice */
|
||||
|
||||
#define APC_FORMATMASK 0xFF0000 /* Mask for apc data formats */
|
||||
|
||||
#define APC_F_PERCENT 0x020000 /* Data in a percent format */
|
||||
#define APC_F_VOLT 0x030000 /* Data in a voltage format */
|
||||
#define APC_F_AMP 0x040000 /* Data in a current/amp format */
|
||||
#define APC_F_CELSIUS 0x050000 /* Data in a temp/C format */
|
||||
#define APC_F_HEX 0x060000 /* Data in a hex number format */
|
||||
#define APC_F_DEC 0x070000 /* Data in a decimal format */
|
||||
#define APC_F_SECONDS 0x100000 /* Time in seconds */
|
||||
#define APC_F_MINUTES 0x110000 /* Time in minutes */
|
||||
#define APC_F_HOURS 0x120000 /* Time in hours */
|
||||
#define APC_F_REASON 0x130000 /* Reason of transfer */
|
||||
#define APC_F_LEAVE 0 /* Just pass this through */
|
||||
|
||||
typedef struct {
|
||||
const char *name; /* the variable name */
|
||||
unsigned int flags; /* various flags */
|
||||
char cmd; /* command character */
|
||||
} apc_vartab_t;
|
||||
|
||||
apc_vartab_t apc_vartab[] = {
|
||||
|
||||
{ "ups.firmware.old", 0, 'V' },
|
||||
{ "ups.firmware", 0, 'b' },
|
||||
{ "ups.firmware.aux", 0, 'v' },
|
||||
{ "ups.model", 0, 0x01 },
|
||||
|
||||
{ "ups.serial", 0, 'n' },
|
||||
{ "ups.mfr.date", 0, 'm' },
|
||||
|
||||
{ "ups.temperature", APC_POLL|APC_F_CELSIUS, 'C' },
|
||||
{ "ups.load", APC_POLL|APC_F_PERCENT, 'P' },
|
||||
|
||||
{ "ups.test.interval", APC_F_HOURS, 'E' },
|
||||
{ "ups.test.result", APC_POLL, 'X' },
|
||||
|
||||
{ "ups.delay.start", APC_F_SECONDS, 'r' },
|
||||
{ "ups.delay.shutdown", APC_F_SECONDS, 'p' },
|
||||
|
||||
{ "ups.id", APC_STRING, 'c' },
|
||||
|
||||
{ "ups.contacts", APC_POLL|APC_F_HEX, 'i' },
|
||||
{ "ups.display.language",
|
||||
0, 0x0C },
|
||||
|
||||
{ "input.voltage", APC_POLL|APC_F_VOLT, 'L' },
|
||||
{ "input.frequency", APC_POLL|APC_F_DEC, 'F' },
|
||||
{ "input.sensitivity", 0, 's' },
|
||||
{ "input.quality", APC_POLL|APC_F_HEX, '9' },
|
||||
|
||||
{ "input.transfer.low", APC_F_VOLT, 'l' },
|
||||
{ "input.transfer.high",
|
||||
APC_F_VOLT, 'u' },
|
||||
{ "input.transfer.reason",
|
||||
APC_POLL|APC_F_REASON, 'G' },
|
||||
|
||||
{ "input.voltage.maximum",
|
||||
APC_POLL|APC_F_VOLT, 'M' },
|
||||
{ "input.voltage.minimum",
|
||||
APC_POLL|APC_F_VOLT, 'N' },
|
||||
|
||||
{ "output.current", APC_POLL|APC_F_AMP, '/' },
|
||||
{ "output.voltage", APC_POLL|APC_F_VOLT, 'O' },
|
||||
{ "output.voltage.nominal",
|
||||
APC_F_VOLT, 'o' },
|
||||
|
||||
{ "ambient.humidity", APC_POLL|APC_F_PERCENT, 'h' },
|
||||
{ "ambient.humidity.high",
|
||||
APC_F_PERCENT, '{' },
|
||||
{ "ambient.humidity.low",
|
||||
APC_F_PERCENT, '}' },
|
||||
|
||||
{ "ambient.temperature",
|
||||
APC_POLL|APC_F_CELSIUS, 't' },
|
||||
{ "ambient.temperature.high",
|
||||
APC_F_CELSIUS, '[' },
|
||||
{ "ambient.temperature.low",
|
||||
APC_F_CELSIUS, ']' },
|
||||
|
||||
{ "battery.date", APC_STRING, 'x' },
|
||||
|
||||
{ "battery.charge", APC_POLL|APC_F_PERCENT, 'f' },
|
||||
{ "battery.charge.restart",
|
||||
APC_F_PERCENT, 'e' },
|
||||
|
||||
{ "battery.voltage", APC_POLL|APC_F_VOLT, 'B' },
|
||||
{ "battery.voltage.nominal",
|
||||
0, 'g' },
|
||||
|
||||
{ "battery.runtime", APC_POLL|APC_F_MINUTES, 'j' },
|
||||
{ "battery.runtime.low",
|
||||
APC_F_MINUTES, 'q' },
|
||||
|
||||
{ "battery.packs", APC_F_DEC, '>' },
|
||||
{ "battery.packs.bad", APC_F_DEC, '<' },
|
||||
{ "battery.alarm.threshold",
|
||||
0, 'k' },
|
||||
/* todo:
|
||||
|
||||
I = alarm enable (hex field) - split into alarm.n.enable
|
||||
J = alarm status (hex field) - split into alarm.n.status
|
||||
|
||||
0x15 = output voltage selection (APC_F_VOLT)
|
||||
0x5C = load power (APC_POLL|APC_F_PERCENT)
|
||||
|
||||
*/
|
||||
|
||||
{NULL, 0, 0},
|
||||
};
|
||||
|
||||
/* ------ instant commands ------ */
|
||||
|
||||
#define APC_CMD_FPTEST 'A'
|
||||
#define APC_CMD_CALTOGGLE 'D'
|
||||
#define APC_CMD_SHUTDOWN 'K'
|
||||
#define APC_CMD_SOFTDOWN 'S'
|
||||
#define APC_CMD_GRACEDOWN '@'
|
||||
#define APC_CMD_SIMPWF 'U'
|
||||
#define APC_CMD_BTESTTOGGLE 'W'
|
||||
#define APC_CMD_OFF 'Z'
|
||||
|
||||
#define APC_CMD_ON 0x0E /* ^N */
|
||||
#define APC_CMD_BYPTOGGLE '^'
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int flags;
|
||||
char cmd;
|
||||
} apc_cmdtab_t;
|
||||
|
||||
apc_cmdtab_t apc_cmdtab[] =
|
||||
{
|
||||
{ "load.off", APC_NASTY|APC_REPEAT, APC_CMD_OFF },
|
||||
{ "load.on", APC_REPEAT, APC_CMD_ON },
|
||||
|
||||
{ "test.panel.start", 0, APC_CMD_FPTEST },
|
||||
|
||||
{ "test.failure.start", 0, APC_CMD_SIMPWF },
|
||||
|
||||
{ "test.battery.start", 0, APC_CMD_BTESTTOGGLE },
|
||||
{ "test.battery.stop", 0, APC_CMD_BTESTTOGGLE },
|
||||
|
||||
{ "shutdown.return.grace",
|
||||
APC_NASTY, APC_CMD_GRACEDOWN },
|
||||
{ "shutdown.return", APC_NASTY, APC_CMD_SOFTDOWN },
|
||||
{ "shutdown.stayoff", APC_NASTY|APC_REPEAT, APC_CMD_SHUTDOWN },
|
||||
|
||||
{ "calibrate.start", 0, APC_CMD_CALTOGGLE },
|
||||
{ "calibrate.stop", 0, APC_CMD_CALTOGGLE },
|
||||
|
||||
{ "bypass.start", 0, APC_CMD_BYPTOGGLE },
|
||||
{ "bypass.stop", 0, APC_CMD_BYPTOGGLE },
|
||||
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
/* compatibility with hardware that doesn't do APC_CMDSET ('a') */
|
||||
|
||||
struct {
|
||||
const char *firmware;
|
||||
const char *cmdchars;
|
||||
int flags;
|
||||
} compat_tab[] = {
|
||||
/* APC Matrix */
|
||||
{ "0XI", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0XM", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0ZI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5UI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5ZM", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
/* APC600 */
|
||||
{ "6QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900 */
|
||||
{ "7QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900I */
|
||||
{ "7II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 2000I */
|
||||
{ "9II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
{ "9GI", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 1250 */
|
||||
{ "8QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* CS 350 */
|
||||
{ "5.4.D", "\1ABPQRSUYbdfgjmnx9", 0 },
|
||||
/* Smart-UPS 600 */
|
||||
{ "D9", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D8", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D7", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D6", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D5", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D4", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
|
||||
{ NULL, NULL, 0 },
|
||||
};
|
1743
drivers/apcsmart.c
1743
drivers/apcsmart.c
File diff suppressed because it is too large
Load diff
|
@ -1,50 +1,88 @@
|
|||
/* apcsmart.h - command table for APC smart protocol units
|
||||
/*
|
||||
* apcsmart.h - common defines for apcsmart driver
|
||||
*
|
||||
* Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
|
||||
* (C) 2000 Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>
|
||||
* (C) 2011 Michal Soltys <soltys@ziu.info>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
|
||||
(C) 2000 Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>
|
||||
#ifndef __apcsmart_h__
|
||||
#define __apcsmart_h__
|
||||
|
||||
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.
|
||||
#define DRIVER_NAME "APC Smart protocol driver"
|
||||
#define DRIVER_VERSION "3.0"
|
||||
|
||||
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.
|
||||
#define ALT_CABLE_1 "940-0095B"
|
||||
|
||||
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
|
||||
*/
|
||||
/*
|
||||
* alerts and other stuff for quick reference:
|
||||
*
|
||||
* $ OL
|
||||
* ! OB
|
||||
* % LB
|
||||
* + not LB anymore
|
||||
* # RB
|
||||
* ? OVER
|
||||
* = not OVER anymore
|
||||
* * powering down now (only older models ?), handled by upsread()
|
||||
* otherwise ignored (it doesn't have to be in ignore sets)
|
||||
*
|
||||
* | eeprom change
|
||||
* & check alarm register for fail
|
||||
* ~ ???
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "serial.h"
|
||||
#include "timehead.h"
|
||||
|
||||
#define APC_TABLE_VERSION "version 2.2"
|
||||
/*
|
||||
* old ones for reference:
|
||||
* #define IGNCHARS "\015+$|!~%?=#&"
|
||||
* #define POLL_IGNORE "\015&|"
|
||||
* #define POLL_ALERT "$!%+#?="
|
||||
* #define MINIGNCHARS "\015+$|!"
|
||||
* notice ~ that was present in IGNCHARS, but not in POLL_IGNORE - this kinda
|
||||
* didn't make sense (?); new versions doesn't filter ~, but keep that in mind
|
||||
* in case something obscure surfaces
|
||||
* due to switch to ICANON tty mode, we removed \015 from ignored characters,
|
||||
* as it's handled by IGNCR at read() level
|
||||
*/
|
||||
|
||||
/* Basic UPS reply line structure */
|
||||
#define ENDCHAR 10 /* APC ends responses with LF */
|
||||
#define ENDCHAR 10 /* APC ends responses with LF (and CR, but it's IGNCRed) */
|
||||
|
||||
/* characters ignored by default */
|
||||
#define IGNCHARS "\015+$|!~%?=#&" /* special characters to ignore */
|
||||
/* what to ignore during alert aware serial reads */
|
||||
#define IGN_AACHARS "|&"
|
||||
|
||||
/* these one is used only during startup, due to ^Z sending certain characters such as # */
|
||||
#define MINIGNCHARS "\015+$|!" /* minimum set of special characters to ignore */
|
||||
/* what alert_handler() should care about */
|
||||
#define ALERT_CHARS "$!%+#?="
|
||||
|
||||
/* normal polls: characters we don't want to parse (including a few alerts) */
|
||||
#define POLL_IGNORE "\015&|"
|
||||
/* characters ignored by alertless reads */
|
||||
#define IGN_CHARS IGN_AACHARS ALERT_CHARS
|
||||
|
||||
/* alert characters we care about - OL, OB, LB, not LB, RB, OVER, not OVER */
|
||||
#define POLL_ALERT "$!%+#?="
|
||||
/*
|
||||
* these ones are used only during capability read, due to ^Z sending certain
|
||||
* characters such as #; it seems it could be equal to just IGN_CHARS w/o #
|
||||
* old: #define IGN_CCCHARS "|$!+"
|
||||
*/
|
||||
#define IGN_CCCHARS "|&$!%+?=" /* capability check ignore set */
|
||||
|
||||
#define UPSDELAY 50000 /* slow down multicharacter commands */
|
||||
#define CMDLONGDELAY 1500000 /* some commands need a 1.5s gap for safety */
|
||||
|
||||
#define SER_WAIT_SEC 3 /* wait up to 3.0 sec for ser_get calls */
|
||||
#define SER_WAIT_USEC 0
|
||||
/*
|
||||
* command set 'a' command reports everything - protocol number, alerts and
|
||||
* supported commands
|
||||
*/
|
||||
#define IGN_CSCHARS "" /* command set ignore set */
|
||||
|
||||
/* dangerous instant commands must be reconfirmed within a 12 second window */
|
||||
#define MINCMDTIME 3
|
||||
|
@ -53,239 +91,61 @@
|
|||
/* it only does two strings, and they're both the same length */
|
||||
#define APC_STRLEN 8
|
||||
|
||||
#define SER_D0 0x001 /* 0 sec., for flushes */
|
||||
#define SER_DX 0x002 /* 200 ms for long/repeated cmds, in case of unexpected NAs */
|
||||
#define SER_D1 0x004 /* 1.5 sec. */
|
||||
#define SER_D3 0x008 /* 3 sec. (default) */
|
||||
#define SER_AA 0x010 /* alert aware set */
|
||||
#define SER_CC 0x020 /* capability check ign set */
|
||||
#define SER_CS 0x040 /* command set ign set */
|
||||
#define SER_TO 0x080 /* timeout allowed */
|
||||
#define SER_HA 0x100 /* handle asterisk */
|
||||
|
||||
|
||||
/* sets of the above (don't test against them, obviously */
|
||||
|
||||
/*
|
||||
* Some cmd codes to ignore (nut doesn't expose those, though the driver might
|
||||
* use them internally (e.g. [a]). If you decide to support them at some
|
||||
* point, remember about removing them from here !
|
||||
*/
|
||||
#define APC_UNR_CMDS "\032\177~')-+8QRYayz"
|
||||
|
||||
/* --------------- */
|
||||
|
||||
/* status bits */
|
||||
|
||||
#define APC_STAT_CAL 1 /* calibration */
|
||||
#define APC_STAT_TRIM 2 /* SmartTrim */
|
||||
#define APC_STAT_BOOST 4 /* SmartBoost */
|
||||
#define APC_STAT_OL 8 /* on line */
|
||||
#define APC_STAT_OB 16 /* on battery */
|
||||
#define APC_STAT_OVER 32 /* overload */
|
||||
#define APC_STAT_LB 64 /* low battery */
|
||||
#define APC_STAT_RB 128 /* replace battery */
|
||||
#define APC_STAT_CAL 0x01 /* calibration */
|
||||
#define APC_STAT_TRIM 0x02 /* SmartTrim */
|
||||
#define APC_STAT_BOOST 0x04 /* SmartBoost */
|
||||
#define APC_STAT_OL 0x08 /* on line */
|
||||
#define APC_STAT_OB 0x10 /* on battery */
|
||||
#define APC_STAT_OVER 0x20 /* overload */
|
||||
#define APC_STAT_LB 0x40 /* low battery */
|
||||
#define APC_STAT_RB 0x80 /* replace battery */
|
||||
|
||||
/* serial protocol: special commands - initialization and such */
|
||||
/*
|
||||
* serial protocol: special commands - initialization and such
|
||||
* these are not exposed as instant commands
|
||||
*/
|
||||
#define APC_STATUS 'Q'
|
||||
#define APC_GOSMART 'Y'
|
||||
#define APC_GODUMB 'R'
|
||||
#define APC_CMDSET 'a'
|
||||
#define APC_CAPABILITY 26 /* ^Z */
|
||||
#define APC_CAPS '\032' /* ^Z */
|
||||
#define APC_NEXTVAL '-'
|
||||
#define APC_FW_OLD 'V'
|
||||
#define APC_FW_NEW 'b'
|
||||
|
||||
/* --------------- */
|
||||
#define APC_LBUF 512
|
||||
#define APC_SBUF 32
|
||||
|
||||
/* Driver command table flag values */
|
||||
/* default a.w.d. value / regex format for command '@' */
|
||||
#define APC_AWDDEF "000"
|
||||
#define APC_AWDFMT "^[0-9]{1,3}$"
|
||||
|
||||
#define APC_POLL 0x0001 /* Poll this variable regularly */
|
||||
#define APC_PRESENT 0x0004 /* Capability seen on this UPS */
|
||||
/* maximum number of supported sdtype methods + regex format*/
|
||||
#define APC_SDMAX "5"
|
||||
#define APC_SDFMT "^[0-5]$"
|
||||
|
||||
#define APC_RW 0x0010 /* read-write variable */
|
||||
#define APC_ENUM 0x0020 /* enumerated type */
|
||||
#define APC_STRING 0x0040 /* string */
|
||||
|
||||
#define APC_NASTY 0x0100 /* Nasty command - take care */
|
||||
#define APC_REPEAT 0x0200 /* Command needs sending twice */
|
||||
|
||||
#define APC_FORMATMASK 0xFF0000 /* Mask for apc data formats */
|
||||
|
||||
#define APC_F_PERCENT 0x020000 /* Data in a percent format */
|
||||
#define APC_F_VOLT 0x030000 /* Data in a voltage format */
|
||||
#define APC_F_AMP 0x040000 /* Data in a current/amp format */
|
||||
#define APC_F_CELSIUS 0x050000 /* Data in a temp/C format */
|
||||
#define APC_F_HEX 0x060000 /* Data in a hex number format */
|
||||
#define APC_F_DEC 0x070000 /* Data in a decimal format */
|
||||
#define APC_F_SECONDS 0x100000 /* Time in seconds */
|
||||
#define APC_F_MINUTES 0x110000 /* Time in minutes */
|
||||
#define APC_F_HOURS 0x120000 /* Time in hours */
|
||||
#define APC_F_REASON 0x130000 /* Reason of transfer */
|
||||
#define APC_F_LEAVE 0 /* Just pass this through */
|
||||
|
||||
typedef struct {
|
||||
const char *name; /* the variable name */
|
||||
unsigned int flags; /* various flags */
|
||||
char cmd; /* command character */
|
||||
} apc_vartab_t;
|
||||
|
||||
apc_vartab_t apc_vartab[] = {
|
||||
|
||||
{ "ups.firmware.old", 0, 'V' },
|
||||
{ "ups.firmware", 0, 'b' },
|
||||
{ "ups.firmware.aux", 0, 'v' },
|
||||
{ "ups.model", 0, 0x01 },
|
||||
|
||||
{ "ups.serial", 0, 'n' },
|
||||
{ "ups.mfr.date", 0, 'm' },
|
||||
|
||||
{ "ups.temperature", APC_POLL|APC_F_CELSIUS, 'C' },
|
||||
{ "ups.load", APC_POLL|APC_F_PERCENT, 'P' },
|
||||
|
||||
{ "ups.test.interval", APC_F_HOURS, 'E' },
|
||||
{ "ups.test.result", APC_POLL, 'X' },
|
||||
|
||||
{ "ups.delay.start", APC_F_SECONDS, 'r' },
|
||||
{ "ups.delay.shutdown", APC_F_SECONDS, 'p' },
|
||||
|
||||
{ "ups.id", APC_STRING, 'c' },
|
||||
|
||||
{ "ups.contacts", APC_POLL|APC_F_HEX, 'i' },
|
||||
{ "ups.display.language",
|
||||
0, 0x0C },
|
||||
|
||||
{ "input.voltage", APC_POLL|APC_F_VOLT, 'L' },
|
||||
{ "input.frequency", APC_POLL|APC_F_DEC, 'F' },
|
||||
{ "input.sensitivity", 0, 's' },
|
||||
{ "input.quality", APC_POLL|APC_F_HEX, '9' },
|
||||
|
||||
{ "input.transfer.low", APC_F_VOLT, 'l' },
|
||||
{ "input.transfer.high",
|
||||
APC_F_VOLT, 'u' },
|
||||
{ "input.transfer.reason",
|
||||
APC_POLL|APC_F_REASON, 'G' },
|
||||
|
||||
{ "input.voltage.maximum",
|
||||
APC_POLL|APC_F_VOLT, 'M' },
|
||||
{ "input.voltage.minimum",
|
||||
APC_POLL|APC_F_VOLT, 'N' },
|
||||
|
||||
{ "output.current", APC_POLL|APC_F_AMP, '/' },
|
||||
{ "output.voltage", APC_POLL|APC_F_VOLT, 'O' },
|
||||
{ "output.voltage.nominal",
|
||||
APC_F_VOLT, 'o' },
|
||||
|
||||
{ "ambient.humidity", APC_POLL|APC_F_PERCENT, 'h' },
|
||||
{ "ambient.humidity.high",
|
||||
APC_F_PERCENT, '{' },
|
||||
{ "ambient.humidity.low",
|
||||
APC_F_PERCENT, '}' },
|
||||
|
||||
{ "ambient.temperature",
|
||||
APC_POLL|APC_F_CELSIUS, 't' },
|
||||
{ "ambient.temperature.high",
|
||||
APC_F_CELSIUS, '[' },
|
||||
{ "ambient.temperature.low",
|
||||
APC_F_CELSIUS, ']' },
|
||||
|
||||
{ "battery.date", APC_STRING, 'x' },
|
||||
|
||||
{ "battery.charge", APC_POLL|APC_F_PERCENT, 'f' },
|
||||
{ "battery.charge.restart",
|
||||
APC_F_PERCENT, 'e' },
|
||||
|
||||
{ "battery.voltage", APC_POLL|APC_F_VOLT, 'B' },
|
||||
{ "battery.voltage.nominal",
|
||||
0, 'g' },
|
||||
|
||||
{ "battery.runtime", APC_POLL|APC_F_MINUTES, 'j' },
|
||||
{ "battery.runtime.low",
|
||||
APC_F_MINUTES, 'q' },
|
||||
|
||||
{ "battery.packs", APC_F_DEC, '>' },
|
||||
{ "battery.packs.bad", APC_F_DEC, '<' },
|
||||
{ "battery.alarm.threshold",
|
||||
0, 'k' },
|
||||
/* todo:
|
||||
|
||||
I = alarm enable (hex field) - split into alarm.n.enable
|
||||
J = alarm status (hex field) - split into alarm.n.status
|
||||
|
||||
0x15 = output voltage selection (APC_F_VOLT)
|
||||
0x5C = load power (APC_POLL|APC_F_PERCENT)
|
||||
|
||||
*/
|
||||
|
||||
{NULL, 0, 0},
|
||||
};
|
||||
|
||||
/* ------ instant commands ------ */
|
||||
|
||||
#define APC_CMD_FPTEST 'A'
|
||||
#define APC_CMD_CALTOGGLE 'D'
|
||||
#define APC_CMD_SHUTDOWN 'K'
|
||||
#define APC_CMD_SOFTDOWN 'S'
|
||||
#define APC_CMD_GRACEDOWN '@'
|
||||
#define APC_CMD_SIMPWF 'U'
|
||||
#define APC_CMD_BTESTTOGGLE 'W'
|
||||
#define APC_CMD_OFF 'Z'
|
||||
|
||||
#define APC_CMD_ON 0x0E /* ^N */
|
||||
#define APC_CMD_BYPTOGGLE '^'
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
int flags;
|
||||
char cmd;
|
||||
} apc_cmdtab_t;
|
||||
|
||||
apc_cmdtab_t apc_cmdtab[] =
|
||||
{
|
||||
{ "load.off", APC_NASTY|APC_REPEAT, APC_CMD_OFF },
|
||||
{ "load.on", APC_REPEAT, APC_CMD_ON },
|
||||
|
||||
{ "test.panel.start", 0, APC_CMD_FPTEST },
|
||||
|
||||
{ "test.failure.start", 0, APC_CMD_SIMPWF },
|
||||
|
||||
{ "test.battery.start", 0, APC_CMD_BTESTTOGGLE },
|
||||
{ "test.battery.stop", 0, APC_CMD_BTESTTOGGLE },
|
||||
|
||||
{ "shutdown.return.grace",
|
||||
APC_NASTY, APC_CMD_GRACEDOWN },
|
||||
{ "shutdown.return", APC_NASTY, APC_CMD_SOFTDOWN },
|
||||
{ "shutdown.stayoff", APC_NASTY|APC_REPEAT, APC_CMD_SHUTDOWN },
|
||||
|
||||
{ "calibrate.start", 0, APC_CMD_CALTOGGLE },
|
||||
{ "calibrate.stop", 0, APC_CMD_CALTOGGLE },
|
||||
|
||||
{ "bypass.start", 0, APC_CMD_BYPTOGGLE },
|
||||
{ "bypass.stop", 0, APC_CMD_BYPTOGGLE },
|
||||
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
/* compatibility with hardware that doesn't do APC_CMDSET ('a') */
|
||||
|
||||
struct {
|
||||
const char *firmware;
|
||||
const char *cmdchars;
|
||||
int flags;
|
||||
} compat_tab[] = {
|
||||
/* APC Matrix */
|
||||
{ "0XI", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0XM", "789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0ZI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5UI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5ZM", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
/* APC600 */
|
||||
{ "6QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900 */
|
||||
{ "7QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900I */
|
||||
{ "7II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 2000I */
|
||||
{ "9II", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
{ "9GI", "79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 1250 */
|
||||
{ "8QD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8QI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TD", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TI", "79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* CS 350 */
|
||||
{ "5.4.D", "\1ABPQRSUYbdfgjmnx9", 0 },
|
||||
/* Smart-UPS 600 */
|
||||
{ "D9", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D8", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D7", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D6", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D5", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D4", "789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
|
||||
{ NULL, NULL, 0 },
|
||||
};
|
||||
#endif
|
||||
|
|
155
drivers/apcsmart_tabs.c
Normal file
155
drivers/apcsmart_tabs.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* apcsmart_tabs.c - common tables for APC smart protocol units
|
||||
*
|
||||
* Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
|
||||
* (C) 2000 Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>
|
||||
* (C) 2011 Michal Soltys <soltys@ziu.info>
|
||||
*
|
||||
* 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 "apcsmart_tabs.h"
|
||||
|
||||
/* APC_MULTI variables *must* be listed in order of preference */
|
||||
apc_vartab_t apc_vartab[] = {
|
||||
|
||||
{ "ups.temperature", 'C', APC_POLL|APC_F_CELSIUS },
|
||||
{ "ups.load", 'P', APC_POLL|APC_F_PERCENT },
|
||||
{ "ups.test.interval", 'E', APC_F_HOURS },
|
||||
{ "ups.test.result", 'X', APC_POLL },
|
||||
{ "ups.delay.start", 'r', APC_F_SECONDS },
|
||||
{ "ups.delay.shutdown", 'p', APC_F_SECONDS },
|
||||
{ "ups.id", 'c', APC_STRING },
|
||||
{ "ups.contacts", 'i', APC_POLL|APC_F_HEX },
|
||||
{ "ups.display.language", '\014', 0 },
|
||||
{ "input.voltage", 'L', APC_POLL|APC_F_VOLT },
|
||||
{ "input.frequency", 'F', APC_POLL|APC_F_DEC },
|
||||
{ "input.sensitivity", 's', 0 },
|
||||
{ "input.quality", '9', APC_POLL|APC_F_HEX },
|
||||
{ "input.transfer.low", 'l', APC_F_VOLT },
|
||||
{ "input.transfer.high", 'u', APC_F_VOLT },
|
||||
{ "input.transfer.reason", 'G', APC_POLL|APC_F_REASON },
|
||||
{ "input.voltage.maximum", 'M', APC_POLL|APC_F_VOLT },
|
||||
{ "input.voltage.minimum", 'N', APC_POLL|APC_F_VOLT },
|
||||
{ "output.current", '/', APC_POLL|APC_F_AMP },
|
||||
{ "output.voltage", 'O', APC_POLL|APC_F_VOLT },
|
||||
{ "output.voltage.nominal", 'o', APC_F_VOLT },
|
||||
{ "ambient.humidity", 'h', APC_POLL|APC_F_PERCENT },
|
||||
{ "ambient.humidity.high", '{', APC_F_PERCENT },
|
||||
{ "ambient.humidity.low", '}', APC_F_PERCENT },
|
||||
{ "ambient.temperature", 't', APC_POLL|APC_F_CELSIUS },
|
||||
{ "ambient.temperature.high", '[', APC_F_CELSIUS },
|
||||
{ "ambient.temperature.low", ']', APC_F_CELSIUS },
|
||||
{ "battery.date", 'x', APC_STRING },
|
||||
{ "battery.charge", 'f', APC_POLL|APC_F_PERCENT },
|
||||
{ "battery.charge.restart", 'e', APC_F_PERCENT },
|
||||
{ "battery.voltage", 'B', APC_POLL|APC_F_VOLT },
|
||||
{ "battery.voltage.nominal", 'g', 0 },
|
||||
{ "battery.runtime", 'j', APC_POLL|APC_F_MINUTES },
|
||||
{ "battery.runtime.low", 'q', APC_F_MINUTES },
|
||||
{ "battery.packs", '>', APC_F_DEC },
|
||||
{ "battery.packs.bad", '<', APC_F_DEC },
|
||||
{ "battery.alarm.threshold", 'k', 0 },
|
||||
{ "ups.serial", 'n', 0 },
|
||||
{ "ups.mfr.date", 'm', 0 },
|
||||
{ "ups.model", '\001', 0 },
|
||||
{ "ups.firmware.aux", 'v', 0 },
|
||||
{ "ups.firmware", 'b', APC_MULTI },
|
||||
{ "ups.firmware", 'V', APC_MULTI },
|
||||
|
||||
{ 0, 0, 0 }
|
||||
/* todo:
|
||||
|
||||
I = alarm enable (hex field) - split into alarm.n.enable
|
||||
J = alarm status (hex field) - split into alarm.n.status
|
||||
|
||||
0x15 = output voltage selection (APC_F_VOLT)
|
||||
0x5C = load power (APC_POLL|APC_F_PERCENT)
|
||||
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* apc commands mapped to nut's instant commands extra values are either
|
||||
* exactly 2-char prefix, or longer than 2-char extended regex
|
||||
*/
|
||||
apc_cmdtab_t apc_cmdtab[] = {
|
||||
{ "test.panel.start", 0, APC_CMD_FPTEST, 0 },
|
||||
{ "test.failure.start", 0, APC_CMD_SIMPWF, 0 },
|
||||
{ "test.battery.start", 0, APC_CMD_BTESTTOGGLE, 0 },
|
||||
{ "test.battery.stop", 0, APC_CMD_BTESTTOGGLE, 0 },
|
||||
{ "shutdown.return", "^at:[0-9]{1,3}$",
|
||||
APC_CMD_GRACEDOWN, APC_NASTY },
|
||||
{ "shutdown.return", "cs", APC_CMD_SOFTDOWN, APC_NASTY },
|
||||
{ "shutdown.return", 0, APC_CMD_SOFTDOWN, APC_NASTY },
|
||||
{ "shutdown.stayoff", 0, APC_CMD_SHUTDOWN, APC_NASTY|APC_REPEAT },
|
||||
{ "load.off", 0, APC_CMD_OFF, APC_NASTY|APC_REPEAT },
|
||||
{ "load.on", 0, APC_CMD_ON, APC_REPEAT },
|
||||
{ "bypass.start", 0, APC_CMD_BYPTOGGLE, 0 },
|
||||
{ "bypass.stop", 0, APC_CMD_BYPTOGGLE, 0 },
|
||||
{ "calibrate.start", 0, APC_CMD_CALTOGGLE, 0 },
|
||||
{ "calibrate.stop", 0, APC_CMD_CALTOGGLE, 0 },
|
||||
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* compatibility with hardware that doesn't do APC_CMDSET ('a') */
|
||||
apc_compattab_t apc_compattab[] = {
|
||||
/* APC Matrix */
|
||||
{ "0XI", "@789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0XM", "@789ABCDEFGKLMNOPQRSTUVWXYZcefgjklmnopqrsuwxz/<>\\^\014\026", 0 },
|
||||
{ "0ZI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5UI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
{ "5ZM", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz/<>", 0 },
|
||||
/* APC600 */
|
||||
{ "6QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "6TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900 */
|
||||
{ "7QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "7TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* SmartUPS 900I */
|
||||
{ "7II", "@79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 2000I */
|
||||
{ "9II", "@79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
{ "9GI", "@79ABCEFGKLMNOPQSUVWXYZcfg", 0 },
|
||||
/* SmartUPS 1250 */
|
||||
{ "8QD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8QI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TD", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
{ "8TI", "@79ABCDEFGKLMNOPQRSUVWXYZcefgjklmnopqrsuxz", 0 },
|
||||
/* CS 350 */
|
||||
{ "5.4.D", "@\1ABPQRSUYbdfgjmnx9", 0 },
|
||||
/* Smart-UPS 600 */
|
||||
{ "D9", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D8", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D7", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D6", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D5", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
{ "D4", "@789ABCEFGKLMNOPQRSUVWXYZ", 0 },
|
||||
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
|
||||
upsdrv_info_t apc_tab_info = {
|
||||
"APC command table",
|
||||
APC_TABLE_VERSION,
|
||||
0,
|
||||
0,
|
||||
{ 0 }
|
||||
};
|
||||
|
100
drivers/apcsmart_tabs.h
Normal file
100
drivers/apcsmart_tabs.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* apcsmart_tabs.h - tables for apcsmart driver
|
||||
*
|
||||
* Copyright (C) 1999 Russell Kroll <rkroll@exploits.org>
|
||||
* (C) 2000 Nigel Metheringham <Nigel.Metheringham@Intechnology.co.uk>
|
||||
* (C) 2011 Michal Soltys <soltys@ziu.info>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __apcsmart_tabs_h__
|
||||
#define __apcsmart_tabs_h__
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#define APC_TABLE_VERSION "version 3.0"
|
||||
|
||||
/* common flags */
|
||||
|
||||
#define APC_PRESENT 0x00000001 /* capability seen on this UPS */
|
||||
|
||||
/* instant commands' flags */
|
||||
|
||||
#define APC_NASTY 0x00000002 /* Nasty command - must be reconfirmed */
|
||||
#define APC_REPEAT 0x00000004 /* Command needs sending twice */
|
||||
|
||||
/* variables' flags */
|
||||
|
||||
#define APC_POLL 0x00000100 /* poll this variable regularly */
|
||||
#define APC_RW 0x00000200 /* read-write variable */
|
||||
#define APC_ENUM 0x00000400 /* enumerated type variable */
|
||||
#define APC_STRING 0x00000800 /* string variable */
|
||||
#define APC_MULTI 0x00001000 /* there're other vars like that */
|
||||
#define APC_DEPR 0x00002000 /* deprecated variable */
|
||||
|
||||
/* variables' format */
|
||||
|
||||
#define APC_F_MASK 0xFF000000 /* Mask for apc data formats */
|
||||
#define APC_F_PERCENT 0x01000000 /* Data in a percent format */
|
||||
#define APC_F_VOLT 0x02000000 /* Data in a voltage format */
|
||||
#define APC_F_AMP 0x03000000 /* Data in a current/amp format */
|
||||
#define APC_F_CELSIUS 0x04000000 /* Data in a temp/C format */
|
||||
#define APC_F_HEX 0x05000000 /* Data in a hex number format */
|
||||
#define APC_F_DEC 0x06000000 /* Data in a decimal format */
|
||||
#define APC_F_SECONDS 0x07000000 /* Time in seconds */
|
||||
#define APC_F_MINUTES 0x08000000 /* Time in minutes */
|
||||
#define APC_F_HOURS 0x09000000 /* Time in hours */
|
||||
#define APC_F_REASON 0x10000000 /* Reason of transfer */
|
||||
#define APC_F_LEAVE 0x00000000 /* Just pass this through */
|
||||
|
||||
/* instant commands */
|
||||
|
||||
#define APC_CMD_OFF 'Z'
|
||||
#define APC_CMD_ON '\016' /* ^N */
|
||||
#define APC_CMD_FPTEST 'A'
|
||||
#define APC_CMD_SIMPWF 'U'
|
||||
#define APC_CMD_BTESTTOGGLE 'W'
|
||||
#define APC_CMD_GRACEDOWN '@'
|
||||
#define APC_CMD_SOFTDOWN 'S'
|
||||
#define APC_CMD_SHUTDOWN 'K'
|
||||
#define APC_CMD_CALTOGGLE 'D'
|
||||
#define APC_CMD_BYPTOGGLE '^'
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *name; /* the variable name */
|
||||
char cmd; /* variable character */
|
||||
unsigned int flags; /* various flags */
|
||||
} apc_vartab_t;
|
||||
|
||||
typedef struct {
|
||||
const char *name, *ext;
|
||||
char cmd;
|
||||
int flags;
|
||||
} apc_cmdtab_t;
|
||||
|
||||
typedef struct {
|
||||
const char *firmware;
|
||||
const char *cmdchars;
|
||||
int flags;
|
||||
} apc_compattab_t;
|
||||
|
||||
extern apc_vartab_t apc_vartab[];
|
||||
extern apc_cmdtab_t apc_cmdtab[];
|
||||
extern apc_compattab_t apc_compattab[];
|
||||
extern upsdrv_info_t apc_tab_info;
|
||||
|
||||
#endif
|
135
drivers/bcmxcp.c
135
drivers/bcmxcp.c
|
@ -19,6 +19,9 @@
|
|||
|
||||
ojw0000 2007Apr5 Oliver Wilcock - modified to control individual load segments (outlet.2.shutdown.return) on Powerware PW5125.
|
||||
|
||||
Modified to support setvar for outlet.n.delay.start by Rich Wrenn (RFW) 9-3-11.
|
||||
Modified to support setvar for outlet.n.delay.shutdown by Arnaud Quette, 9-12-11
|
||||
|
||||
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
|
||||
|
@ -109,18 +112,22 @@ TODO List:
|
|||
|
||||
Implement support for Password Authorization (XCP spec, §4.3.2)
|
||||
|
||||
Implement support for settable variables (upsh.setvar)
|
||||
Complete support for settable variables (upsh.setvar)
|
||||
*/
|
||||
|
||||
|
||||
#include "main.h"
|
||||
#include <math.h> /* For ldexp() */
|
||||
#include <float.h> /*for FLT_MAX */
|
||||
#include "nut_stdint.h" /* for uint8_t, uint16_t, uint32_t, ... */
|
||||
#include "bcmxcp_io.h"
|
||||
#include "bcmxcp.h"
|
||||
|
||||
#define DRIVER_NAME "BCMXCP UPS driver"
|
||||
#define DRIVER_VERSION "0.24"
|
||||
#define DRIVER_VERSION "0.25"
|
||||
|
||||
#define MAX_NUT_NAME_LENGTH 128
|
||||
#define NUT_OUTLET_POSITION 7
|
||||
|
||||
/* driver description structure */
|
||||
upsdrv_info_t upsdrv_info = {
|
||||
|
@ -148,6 +155,7 @@ static void init_ups_alarm_map(const unsigned char *map, unsigned char len);
|
|||
static void decode_meter_map_entry(const unsigned char *entry, const unsigned char format, char* value);
|
||||
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);
|
||||
|
||||
|
||||
const char *FreqTol[3] = {"+/-2%", "+/-5%", "+/-7"};
|
||||
|
@ -881,8 +889,8 @@ int init_outlet(unsigned char len)
|
|||
res = command_read_sequence(PW_OUT_MON_BLOCK_REQ, answer);
|
||||
if (res <= 0)
|
||||
fatal_with_errno(EXIT_FAILURE, "Could not communicate with the ups");
|
||||
else
|
||||
upsdebugx(1, "init_outlet(%i), res=%i", len, res);
|
||||
else
|
||||
upsdebugx(1, "init_outlet(%i), res=%i", len, res);
|
||||
|
||||
num_outlet = answer[iIndex++];
|
||||
upsdebugx(2, "Number of outlets: %d\n", num_outlet);
|
||||
|
@ -906,12 +914,16 @@ else
|
|||
upsdebugx(2, "Auto delay off: %d\n", auto_dly_off);
|
||||
snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%d.delay.shutdown", num);
|
||||
dstate_setinfo(outlet_name, "%d", auto_dly_off);
|
||||
dstate_setflags(outlet_name, ST_FLAG_RW | ST_FLAG_STRING);
|
||||
dstate_setaux(outlet_name, 5);
|
||||
|
||||
auto_dly_on = get_word(answer+iIndex);
|
||||
iIndex += 2;
|
||||
upsdebugx(2, "Auto delay on: %d\n", auto_dly_on);
|
||||
snprintf(outlet_name, sizeof(outlet_name)-1, "outlet.%d.delay.start", num);
|
||||
dstate_setinfo(outlet_name, "%d", auto_dly_on);
|
||||
dstate_setflags(outlet_name, ST_FLAG_RW | ST_FLAG_STRING);
|
||||
dstate_setaux(outlet_name, 5);
|
||||
}
|
||||
|
||||
return num_outlet;
|
||||
|
@ -1221,6 +1233,7 @@ void upsdrv_initinfo(void)
|
|||
dstate_addcmd("test.battery.start");
|
||||
|
||||
upsh.instcmd = instcmd;
|
||||
upsh.setvar = setvar;
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1465,9 +1478,11 @@ void upsdrv_shutdown(void)
|
|||
|
||||
static int instcmd(const char *cmdname, const char *extra)
|
||||
{
|
||||
unsigned char answer[5], cbuf[6];
|
||||
|
||||
unsigned char answer[128], cbuf[6];
|
||||
char varname[32];
|
||||
const char *varvalue = NULL;
|
||||
int res, sec;
|
||||
int sddelay = 0x03; /* outlet off in 3 seconds, by default */
|
||||
|
||||
upsdebugx(1, "entering instcmd(%s)", cmdname);
|
||||
|
||||
|
@ -1480,9 +1495,15 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
|
||||
sleep(1); /* 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));
|
||||
}
|
||||
|
||||
cbuf[0] = PW_LOAD_OFF_RESTART;
|
||||
cbuf[1] = 0x03; /* outlet off in 3 seconds */
|
||||
cbuf[2] = 0x00; /* high byte of the 2 byte time argument */
|
||||
cbuf[1] = sddelay & 0xff;
|
||||
cbuf[2] = sddelay >> 8; /* high byte of the 2 byte time argument */
|
||||
cbuf[3] = ( '1' == cmdname[7] ? 0x01 : 0x02); /* which outlet load segment? Assumes '1' or '2' at position 8 of the command string. */
|
||||
|
||||
/* ojw00000 the following copied from command "shutdown.return" below 2007Apr5 */
|
||||
|
@ -1586,7 +1607,7 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
break;
|
||||
}
|
||||
case 0x33: {
|
||||
upslogx(LOG_NOTICE, "[%s] disbled by front panel", cmdname);
|
||||
upslogx(LOG_NOTICE, "[%s] disabled by front panel", cmdname);
|
||||
return STAT_INSTCMD_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
@ -1596,7 +1617,8 @@ static int instcmd(const char *cmdname, const char *extra)
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
upslogx(LOG_NOTICE, "[%s] not supported", cmdname);
|
||||
upslogx(LOG_NOTICE, "[%s] not supported (code %c)",
|
||||
cmdname, (unsigned char) answer[0]);
|
||||
return STAT_INSTCMD_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
@ -1667,3 +1689,96 @@ void upsdrv_makevartable(void)
|
|||
addvar(VAR_VALUE, "baud_rate", "Specify communication speed (ex: 9600)");
|
||||
}
|
||||
|
||||
int setvar (const char *varname, const char *val)
|
||||
{
|
||||
unsigned char answer[128], cbuf[5];
|
||||
char namebuf[MAX_NUT_NAME_LENGTH];
|
||||
int res, sec, outlet_num;
|
||||
int onOff_setting = PW_AUTO_OFF_DELAY;
|
||||
|
||||
upsdebugx(1, "entering setvar(%s, %s)", varname, val);
|
||||
|
||||
strncpy(namebuf, varname, sizeof(namebuf));
|
||||
namebuf[NUT_OUTLET_POSITION] = 'n'; /* Assumes a maximum of 9 outlets */
|
||||
|
||||
if ( (strcasecmp(namebuf, "outlet.n.delay.start")) &&
|
||||
(strcasecmp(namebuf, "outlet.n.delay.shutdown")) ) {
|
||||
return STAT_SET_UNKNOWN;
|
||||
}
|
||||
|
||||
if (outlet_block_len <= 8) {
|
||||
return STAT_SET_INVALID;
|
||||
}
|
||||
|
||||
if (!strcasecmp(namebuf, "outlet.n.delay.start")) {
|
||||
onOff_setting = PW_AUTO_ON_DELAY;
|
||||
}
|
||||
|
||||
send_write_command(AUTHOR, 4);
|
||||
/* Need to. Have to wait at least 0.25 sec max 16 sec */
|
||||
sleep (1);
|
||||
|
||||
outlet_num = varname[NUT_OUTLET_POSITION] - '0';
|
||||
if (outlet_num < 1 || outlet_num > 9) {
|
||||
return STAT_SET_INVALID;
|
||||
}
|
||||
|
||||
sec = atoi(val);
|
||||
/* Check value:
|
||||
* 0-32767 are valid values
|
||||
* -1 means no Automatic off or restart
|
||||
* for Auto Off Delay:
|
||||
* 0-30 are valid but ill-advised */
|
||||
if (sec < -1 || sec > 0x7FFF) {
|
||||
return STAT_SET_INVALID;
|
||||
}
|
||||
|
||||
cbuf[0] = PW_SET_OUTLET_COMMAND; /* Cmd */
|
||||
cbuf[1] = onOff_setting; /* Set Auto Off (1) or On (2) Delay */
|
||||
cbuf[2] = outlet_num; /* Outlet number */
|
||||
cbuf[3] = sec&0xff; /* Delay in seconds LSB */
|
||||
cbuf[4] = sec>>8; /* Delay in seconds MSB */
|
||||
|
||||
res = command_write_sequence(cbuf, 5, answer);
|
||||
if (res <= 0) {
|
||||
upslogx(LOG_ERR, "Short read from UPS");
|
||||
dstate_datastale();
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch ((unsigned char) answer[0]) {
|
||||
|
||||
case 0x31: {
|
||||
upslogx(LOG_NOTICE,"Outlet %d %s delay set to %d sec",
|
||||
outlet_num, (onOff_setting == PW_AUTO_ON_DELAY)?"start":"shutdown", sec);
|
||||
dstate_setinfo(varname, "%d", sec);
|
||||
return STAT_SET_HANDLED;
|
||||
break;
|
||||
}
|
||||
case 0x33: {
|
||||
upslogx(LOG_NOTICE, "Set [%s] failed due to UPS busy", varname);
|
||||
/* TODO: we should probably retry... */
|
||||
return STAT_SET_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
case 0x35: {
|
||||
upslogx(LOG_NOTICE, "Set [%s %s] failed due to parameter out of range", varname, val);
|
||||
return STAT_SET_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
case 0x36: {
|
||||
upslogx(LOG_NOTICE, "Set [%s %s] failed due to invalid parameter", varname, val);
|
||||
return STAT_SET_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
upslogx(LOG_NOTICE, "Set [%s] not supported", varname);
|
||||
return STAT_SET_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return STAT_SET_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -42,6 +42,24 @@
|
|||
#define PW_INIT_BAT_TEST (unsigned char)0xB1 /* Initiate battery test command. length 3 */
|
||||
#define PW_INIT_SYS_TEST (unsigned char)0xB2 /* Initiate general system test command. length 2 */
|
||||
|
||||
/* Define the XCP ACK block responses */
|
||||
#define XCPRESP_ACK 0x31 /* Accepted and executed */
|
||||
#define XCPRESP_NOT_IMPL 0x32 /* Recognized, but not implemented */
|
||||
#define XCPRESP_BUSY 0x33 /* Recognized, but Busy and not executed */
|
||||
#define XCPRESP_UNRECOGN 0x34 /* Unrecognized cmd */
|
||||
#define XCPRESP_OUT_RANGE 0x35 /* Parameter was out of range; not executed */
|
||||
#define XCPRESP_PRM_INVLD 0x36 /* Parameter invalid; not executed */
|
||||
#define XCPRESP_PRM_ADJST 0x37 /* Parameter adjusted to nearest good value */
|
||||
#define XCPRESP_PRM_RDONLY 0x38 /* Parameter is Read-only - cannot be written (at this privilege level) */
|
||||
|
||||
/* Outlet operations */
|
||||
#define PW_ALL_OUTLETS 0
|
||||
#define PW_AUTO_OFF_DELAY 1
|
||||
#define PW_AUTO_ON_DELAY 2
|
||||
/* 0 means Abort countdown */
|
||||
#define PW_TURN_OFF_DELAY 3
|
||||
#define PW_TURN_ON_DELAY 4
|
||||
|
||||
/* Config block offsets */
|
||||
#define BCMXCP_CONFIG_BLOCK_MACHINE_TYPE_CODE 0
|
||||
#define BCMXCP_CONFIG_BLOCK_MODEL_NUMBER 2
|
||||
|
|
|
@ -197,7 +197,7 @@ int get_answer(unsigned char *data, unsigned char command)
|
|||
static int command_sequence(unsigned char *command, int command_length, unsigned char *answer)
|
||||
{
|
||||
int bytes_read, retry = 0;
|
||||
|
||||
|
||||
while (retry++ < PW_MAX_TRY) {
|
||||
|
||||
if (retry == PW_MAX_TRY) {
|
||||
|
|
|
@ -260,13 +260,10 @@ void upsdrv_updateinfo(void)
|
|||
double ampsout=0.0, vbatt=0.0, battpercent=0.0, loadpercent=0.0,
|
||||
upstemp=0.0, acfreq=0.0;
|
||||
|
||||
char date[9], time[9], tmp[32];
|
||||
char tmp[32];
|
||||
|
||||
upsdebugx(3, "f response: %d %s", (int)strlen(fstring), fstring);
|
||||
|
||||
date[0]='\0';
|
||||
time[0]='\0';
|
||||
|
||||
/* Inverter status. 0=off 1=on */
|
||||
inverter = bcd2i(&fstring[16], 2);
|
||||
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
* http://powerquality.eaton.com/Support/Software-Drivers/Downloads/connectivity-firmware/bestpwr2.mib
|
||||
*/
|
||||
|
||||
/* TODO: find the right sysOID for this MIB
|
||||
* #define BESTPOWER_SYSOID ".1.3.6.1.4.1.2947???"
|
||||
*/
|
||||
|
||||
static info_lkp_t bestpower_power_status[] = {
|
||||
{ 1, "OL" },
|
||||
{ 2, "OB" },
|
||||
|
|
|
@ -75,6 +75,7 @@ static const struct {
|
|||
{ "megatec", "Q1\r", "F\r", "I\r" },
|
||||
{ "mustek", "QS\r", "F\r", "I\r" },
|
||||
{ "megatec/old", "D\r", "F\r", "I\r" },
|
||||
{ "zinto", "Q1\r", "F\r", "FW?\r" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -472,6 +473,8 @@ void blazer_makevartable(void)
|
|||
|
||||
addvar(VAR_FLAG, "norating", "Skip reading rating information from UPS");
|
||||
addvar(VAR_FLAG, "novendor", "Skip reading vendor information from UPS");
|
||||
|
||||
addvar(VAR_FLAG, "protocol", "Preselect communication protocol (skip autodetection)");
|
||||
}
|
||||
|
||||
|
||||
|
@ -594,12 +597,18 @@ static void blazer_initbattery(void)
|
|||
|
||||
void blazer_initinfo(void)
|
||||
{
|
||||
const char *protocol = getval("protocol");
|
||||
int retry;
|
||||
|
||||
for (proto = 0; command[proto].status; proto++) {
|
||||
|
||||
int ret;
|
||||
|
||||
if (protocol && strcasecmp(protocol, command[proto].name)) {
|
||||
upsdebugx(2, "Skipping %s protocol...", command[proto].name);
|
||||
continue;
|
||||
}
|
||||
|
||||
upsdebugx(2, "Trying %s protocol...", command[proto].name);
|
||||
|
||||
for (retry = 1; retry <= MAXTRIES; retry++) {
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
*/
|
||||
|
||||
#define APHEL1_OID_MIB ".1.3.6.1.4.1.17373"
|
||||
#define APHEL1_SYSOID APHEL1_OID_MIB
|
||||
#define APHEL1_OID_MODEL_NAME ".1.3.6.1.4.1.17373.3.1.1.0"
|
||||
#define APHEL1_OID_FIRMREV ".1.3.6.1.4.1.17373.3.1.2.0"
|
||||
#define APHEL1_OID_DEVICE_NAME ".1.3.6.1.4.1.17373.3.1.3.0"
|
||||
|
@ -83,9 +84,9 @@ static snmp_info_t eaton_aphel_genesisII_mib[] = {
|
|||
/* APHEL PDU-MIB - Revelation MIB (Managed ePDU)
|
||||
* ********************************************* */
|
||||
|
||||
#define AR_BASE_OID ".1.3.6.1.4.1.534.6.6.6"
|
||||
|
||||
#define APHEL2_OID_MODEL_NAME AR_OID_MODEL_NAME
|
||||
#define AR_BASE_OID ".1.3.6.1.4.1.534.6.6.6"
|
||||
#define APHEL2_SYSOID AR_BASE_OID
|
||||
#define APHEL2_OID_MODEL_NAME AR_OID_MODEL_NAME
|
||||
|
||||
#define AR_OID_MODEL_NAME AR_BASE_OID ".1.1.12.0"
|
||||
#define AR_OID_DEVICE_NAME AR_BASE_OID ".1.1.13.0"
|
||||
|
@ -207,5 +208,138 @@ static snmp_info_t eaton_aphel_revelation_mib[] = {
|
|||
{ NULL, 0, 0, NULL, NULL, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
mib2nut_info_t aphel_genesisII = { "aphel_genesisII", EATON_APHEL_MIB_VERSION, "", APHEL1_OID_MODEL_NAME, eaton_aphel_genesisII_mib };
|
||||
mib2nut_info_t aphel_revelation = { "aphel_revelation", EATON_APHEL_MIB_VERSION, "", APHEL2_OID_MODEL_NAME, eaton_aphel_revelation_mib };
|
||||
/* Eaton PDU-MIB - Marlin MIB
|
||||
* ************************** */
|
||||
|
||||
#define EATON_MARLIN_MIB_VERSION "0.05"
|
||||
#define EATON_MARLIN_SYSOID ".1.3.6.1.4.1.534.6.6.7"
|
||||
#define EATON_MARLIN_OID_MODEL_NAME ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.0"
|
||||
|
||||
static info_lkp_t marlin_outlet_status_info[] = {
|
||||
{ 0, "off" },
|
||||
{ 1, "on" },
|
||||
{ 2, "pendingOff" }, /* transitional status */
|
||||
{ 3, "pendingOn" }, /* transitional status */
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Snmp2NUT lookup table for Eaton Marlin MIB */
|
||||
static snmp_info_t eaton_marlin_mib[] = {
|
||||
/* Device page */
|
||||
{ "device.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON",
|
||||
SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL, NULL },
|
||||
{ "device.model", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.2.0",
|
||||
"Eaton Powerware ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
{ "device.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.4.0",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
{ "device.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu",
|
||||
SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL, NULL },
|
||||
/* FIXME: need RFC validation on this variable
|
||||
* { "device.part", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.3.0",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL }, */
|
||||
|
||||
/* UPS page */
|
||||
{ "ups.mfr", ST_FLAG_STRING, SU_INFOSIZE, NULL, "EATON",
|
||||
SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL, NULL },
|
||||
{ "ups.model", ST_FLAG_STRING, SU_INFOSIZE, "1.3.6.1.4.1.534.6.6.7.1.2.1.2.0",
|
||||
"Eaton Powerware ePDU", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
|
||||
/* FIXME: use unitName.0 (ePDU)?
|
||||
* { "ups.id", ST_FLAG_STRING, SU_INFOSIZE, AR_OID_DEVICE_NAME,
|
||||
"unknown", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL }, */
|
||||
{ "ups.serial", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.4.0",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
{ "ups.firmware", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.5.0",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL },
|
||||
{ "ups.type", ST_FLAG_STRING, SU_INFOSIZE, NULL, "pdu",
|
||||
SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL, NULL },
|
||||
/* TODO:
|
||||
* The below possibly requires (?) the use of
|
||||
* int snprint_hexstring(char *buf, size_t buf_len, const u_char *, size_t);
|
||||
* { "ups.macaddr", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.2.1.2.2.1.6.2",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
* + date reformating callback
|
||||
* 2011-8-29,16:27:25.0,+1:0
|
||||
* Hex-STRING: 07 DB 08 1D 10 0C 36 00 2B 01 00 00
|
||||
* { "ups.date", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.8.0",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
* { "ups.time", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.1.2.1.8.0",
|
||||
"", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
*/
|
||||
|
||||
/* Input page */
|
||||
{ "input.phases", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.20.0", NULL, SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
/* inputType.0.1 singlePhase (1) iso.3.6.1.4.1.534.6.6.7.3.1.1.2.0.1 */
|
||||
{ "input.frequency", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.3.0.1", NULL, 0, NULL, NULL },
|
||||
{ "input.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.0.1.1", NULL, 0, NULL, NULL },
|
||||
/* FIXME: check multiplier */
|
||||
{ "input.current", 0, 0.01, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.0.1.1", NULL, 0, NULL, NULL },
|
||||
|
||||
/* Ambient page */
|
||||
/* We use critical levels, for both temperature and humidity,
|
||||
* since warning levels are also available! */
|
||||
{ "ambient.temperature", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.4.0.1", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.temperature.low", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.7.0.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.temperature.high", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.1.1.9.0.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.humidity", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.4.0.1", NULL, SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.humidity.low", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.7.0.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL, NULL },
|
||||
{ "ambient.humidity.high", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.7.2.1.9.0.1", NULL, SU_FLAG_NEGINVALID | SU_FLAG_OK, NULL, NULL },
|
||||
|
||||
/* Outlet page */
|
||||
{ "outlet.id", 0, 1, NULL, "0", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL, NULL },
|
||||
{ "outlet.desc", ST_FLAG_RW | ST_FLAG_STRING, 20, NULL, "All outlets",
|
||||
SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK, NULL, NULL },
|
||||
{ "outlet.count", 0, 1, ".1.3.6.1.4.1.534.6.6.7.1.2.1.22.0", "0", SU_FLAG_STATIC | SU_FLAG_OK, NULL, NULL },
|
||||
/* The below ones are the same as the input.* equivalent */
|
||||
{ "outlet.frequency", 0, 0.1, ".1.3.6.1.4.1.534.6.6.7.3.1.1.3.0.1", NULL, 0, NULL, NULL },
|
||||
{ "outlet.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.3.2.1.3.0.1.1", NULL, 0, NULL, NULL },
|
||||
{ "outlet.current", 0, 0.01, ".1.3.6.1.4.1.534.6.6.7.3.3.1.4.0.1.1", NULL, 0, NULL, NULL },
|
||||
/* There is also a .2 available (ie .1.3.6.1.4.1.534.6.6.7.3.4.1.3.0.1.2) */
|
||||
{ "outlet.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.4.0.1.2", NULL, 0, NULL, NULL },
|
||||
/* There is also a .2 available (ie .1.3.6.1.4.1.534.6.6.7.3.4.1.3.0.1.2) */
|
||||
{ "outlet.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.3.4.1.3.0.1.1", NULL, 0, NULL, NULL },
|
||||
|
||||
/* outlet template definition
|
||||
* Indexes start from 1, ie outlet.1 => <OID>.1 */
|
||||
{ "outlet.%i.switchable", 0, 1, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.0.%i", "yes", SU_FLAG_STATIC | SU_OUTLET, NULL, NULL },
|
||||
/* Note: the first definition is used to determine the base index (ie 0 or 1) */
|
||||
{ "outlet.%i.desc", ST_FLAG_RW | ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.1.1.3.0.%i", NULL, SU_FLAG_STATIC | SU_FLAG_OK | SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.status", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.534.6.6.7.6.6.1.2.0.%i",
|
||||
NULL, SU_FLAG_OK | SU_OUTLET, &marlin_outlet_status_info[0], NULL },
|
||||
/* FIXME: or use ".1.3.6.1.4.1.534.6.6.7.6.1.1.2.0.1", though it's related to groups! */
|
||||
{ "outlet.%i.id", 0, 1, NULL, "%i", SU_FLAG_STATIC | SU_FLAG_ABSENT | SU_FLAG_OK | SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.current", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.4.1.3.0.%i", NULL, SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.realpower", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.6.5.1.3.0.%i", NULL, SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.voltage", 0, 0.001, ".1.3.6.1.4.1.534.6.6.7.6.3.1.2.0.%i", NULL, SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.power", 0, 1.0, ".1.3.6.1.4.1.534.6.6.7.6.5.1.2.0.%i", NULL, SU_OUTLET, NULL, NULL },
|
||||
|
||||
/* TODO: handle statistics
|
||||
* outletWh.0.1
|
||||
* outletWhTimer.0.1
|
||||
*/
|
||||
|
||||
/* instant commands. */
|
||||
/* Notes:
|
||||
* - load.cycle might be replaced by / mapped on shutdown.reboot
|
||||
* - outletControl{Off,On,Reboot}Cmd values:
|
||||
* 0-n : Timer
|
||||
* -1 : Cancel
|
||||
* we currently use "0", so instant On | Off | Reboot... */
|
||||
/* no counterpart found!
|
||||
{ "outlet.load.off", 0, DO_OFF, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL, NULL },
|
||||
{ "outlet.load.on", 0, DO_ON, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL, NULL },
|
||||
{ "outlet.load.cycle", 0, DO_CYCLE, AR_OID_OUTLET_STATUS ".0", NULL, SU_TYPE_CMD, NULL, NULL }, */
|
||||
|
||||
/* TODO: handle delays */
|
||||
{ "outlet.%i.load.off", 0, 0, ".1.3.6.1.4.1.534.6.6.7.6.6.1.3.0.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.load.on", 0, 0, ".1.3.6.1.4.1.534.6.6.7.6.6.1.4.0.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL, NULL },
|
||||
{ "outlet.%i.load.cycle", 0, 0, ".1.3.6.1.4.1.534.6.6.7.6.6.1.5.0.%i", NULL, SU_TYPE_CMD | SU_OUTLET, NULL, NULL },
|
||||
|
||||
/* end of structure. */
|
||||
{ NULL, 0, 0, NULL, NULL, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
mib2nut_info_t aphel_genesisII = { "aphel_genesisII", EATON_APHEL_MIB_VERSION, "", APHEL1_OID_MODEL_NAME, eaton_aphel_genesisII_mib, APHEL1_SYSOID };
|
||||
mib2nut_info_t aphel_revelation = { "aphel_revelation", EATON_APHEL_MIB_VERSION, "", APHEL2_OID_MODEL_NAME, eaton_aphel_revelation_mib, APHEL2_SYSOID };
|
||||
mib2nut_info_t eaton_marlin = { "eaton_epdu", EATON_MARLIN_MIB_VERSION, "", EATON_MARLIN_OID_MODEL_NAME, eaton_marlin_mib, EATON_MARLIN_SYSOID };
|
||||
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
|
||||
extern mib2nut_info_t aphel_genesisII;
|
||||
extern mib2nut_info_t aphel_revelation;
|
||||
extern mib2nut_info_t eaton_marlin;
|
||||
|
||||
#endif /* EATON_MIB_H */
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
/* SNMP OIDs set */
|
||||
#define IETF_OID_UPS_MIB "1.3.6.1.2.1.33.1."
|
||||
#define IETF_SYSOID ".1.3.6.1.2.1.33"
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
|
@ -273,4 +274,4 @@ static snmp_info_t ietf_mib[] = {
|
|||
{ NULL, 0, 0, NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
mib2nut_info_t ietf = { "ietf", IETF_MIB_VERSION, IETF_OID_UPS_MIB "4.1.0", IETF_OID_UPS_MIB "1.1.0", ietf_mib };
|
||||
mib2nut_info_t ietf = { "ietf", IETF_MIB_VERSION, IETF_OID_UPS_MIB "4.1.0", IETF_OID_UPS_MIB "1.1.0", ietf_mib, IETF_SYSOID };
|
||||
|
|
|
@ -358,7 +358,6 @@ void do_upsconf_args(char *confupsname, char *var, char *val)
|
|||
}
|
||||
|
||||
/* everything else must be for the driver */
|
||||
|
||||
storeval(var, val);
|
||||
}
|
||||
|
||||
|
@ -556,10 +555,6 @@ int main(int argc, char **argv)
|
|||
"Error: you must specify a port name in ups.conf. Try -h for help.");
|
||||
}
|
||||
|
||||
pidfn = xmalloc(SMALLBUF);
|
||||
|
||||
snprintf(pidfn, SMALLBUF, "%s/%s-%s.pid", altpidpath(), progname, upsname);
|
||||
|
||||
upsdebugx(1, "debug level is '%d'", nut_debug_level);
|
||||
|
||||
new_uid = get_user_pwent(user);
|
||||
|
@ -574,7 +569,39 @@ int main(int argc, char **argv)
|
|||
if ((!do_forceshutdown) && (chdir(dflt_statepath())))
|
||||
fatal_with_errno(EXIT_FAILURE, "Can't chdir to %s", dflt_statepath());
|
||||
|
||||
setup_signals();
|
||||
/* Setup signals to communicate with driver once backgrounded. */
|
||||
if ((nut_debug_level == 0) && (!do_forceshutdown)) {
|
||||
char buffer[SMALLBUF];
|
||||
|
||||
setup_signals();
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s-%s.pid", altpidpath(), progname, upsname);
|
||||
|
||||
/* Try to prevent that driver is started multiple times. If a PID file */
|
||||
/* already exists, send a TERM signal to the process and try if it goes */
|
||||
/* away. If not, retry a couple of times. */
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct stat st;
|
||||
|
||||
if (stat(buffer, &st) != 0) {
|
||||
/* PID file not found */
|
||||
break;
|
||||
}
|
||||
|
||||
if (sendsignalfn(buffer, SIGTERM) != 0) {
|
||||
/* Can't send signal to PID, assume invalid file */
|
||||
break;
|
||||
}
|
||||
|
||||
upslogx(LOG_WARNING, "Duplicate driver instance detected! Terminating other driver!");
|
||||
|
||||
/* Allow driver some time to quit */
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
pidfn = xstrdup(buffer);
|
||||
writepid(pidfn); /* before backgrounding */
|
||||
}
|
||||
|
||||
/* clear out callback handler data */
|
||||
memset(&upsh, '\0', sizeof(upsh));
|
||||
|
@ -643,7 +670,7 @@ int main(int argc, char **argv)
|
|||
|
||||
if (nut_debug_level == 0) {
|
||||
background();
|
||||
writepid(pidfn);
|
||||
writepid(pidfn); /* PID changes when backgrounding */
|
||||
}
|
||||
|
||||
while (!exit_flag) {
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "usbhid-ups.h"
|
||||
#include "mge-hid.h"
|
||||
|
||||
#define MGE_HID_VERSION "MGE HID 1.21"
|
||||
#define MGE_HID_VERSION "MGE HID 1.27"
|
||||
|
||||
/* (prev. MGE Office Protection Systems, prev. MGE UPS SYSTEMS) */
|
||||
/* Eaton */
|
||||
|
@ -59,8 +59,12 @@ static usb_device_id_t mge_usb_device_table[] = {
|
|||
#endif
|
||||
|
||||
typedef enum {
|
||||
MGE_DEFAULT = 0,
|
||||
MGE_EVOLUTION = 0x100, /* MGE Evolution series */
|
||||
MGE_DEFAULT_OFFLINE = 0,
|
||||
MGE_PEGASUS = 0x100,
|
||||
MGE_3S = 0x110,
|
||||
/* All offline models have type value < 200! */
|
||||
MGE_DEFAULT = 0x200, /* for line-interactive and online models */
|
||||
MGE_EVOLUTION = 0x300, /* MGE Evolution series */
|
||||
MGE_EVOLUTION_650,
|
||||
MGE_EVOLUTION_850,
|
||||
MGE_EVOLUTION_1150,
|
||||
|
@ -70,14 +74,29 @@ typedef enum {
|
|||
MGE_EVOLUTION_2000,
|
||||
MGE_EVOLUTION_S_2500,
|
||||
MGE_EVOLUTION_S_3000,
|
||||
MGE_PULSAR_M = 0x200, /* MGE Pulsar M series */
|
||||
MGE_PULSAR_M = 0x400, /* MGE Pulsar M series */
|
||||
MGE_PULSAR_M_2200,
|
||||
MGE_PULSAR_M_3000,
|
||||
MGE_PULSAR_M_3000_XL,
|
||||
MGE_PEGASUS = 0x400
|
||||
MGE_PULSAR_M_3000_XL
|
||||
} models_type_t;
|
||||
|
||||
/* Default to line-interactive or online (ie, not offline).
|
||||
* This is then overriden for offline, through mge_model_names */
|
||||
static models_type_t mge_type = MGE_DEFAULT;
|
||||
|
||||
/* Countries definition, for region specific settings and features */
|
||||
typedef enum {
|
||||
COUNTRY_UNKNOWN = -1,
|
||||
COUNTRY_EUROPE = 0,
|
||||
COUNTRY_US,
|
||||
/* Special European models, which also supports 200 / 208 V */
|
||||
COUNTRY_EUROPE_208,
|
||||
COUNTRY_WORLDWIDE,
|
||||
COUNTRY_AUSTRALIA,
|
||||
} country_code_t;
|
||||
|
||||
static int country_code = COUNTRY_UNKNOWN;
|
||||
|
||||
static char mge_scratch_buf[20];
|
||||
|
||||
/* The HID path 'UPS.PowerSummary.Time' reports Unix time (ie the number of
|
||||
|
@ -279,14 +298,19 @@ info_lkp_t mge_onbatt_info[] = {
|
|||
{ 0, "online", NULL },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
/* allow limiting to ups.model ~= Protection Station */
|
||||
|
||||
/* allow limiting to ups.model = Protection Station, Ellipse Eco
|
||||
* and 3S (US 750 and AUS 700 only!) */
|
||||
static const char *eaton_check_pegasus_fun(double value)
|
||||
{
|
||||
switch (mge_type & 0xFF00) /* Ignore model byte */
|
||||
{
|
||||
case MGE_PEGASUS:
|
||||
break;
|
||||
|
||||
case MGE_3S:
|
||||
/* Only consider non European models */
|
||||
if (country_code != COUNTRY_EUROPE)
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -302,6 +326,22 @@ static info_lkp_t pegasus_threshold_info[] = {
|
|||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Determine country using UPS.PowerSummary.Country.
|
||||
* If not present:
|
||||
* if PowerConverter.Output.Voltage >= 200 => "Europe"
|
||||
* else default to "US" */
|
||||
static const char *eaton_check_country_fun(double value)
|
||||
{
|
||||
country_code = value;
|
||||
/* Return NULL, not to get the value published! */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static info_lkp_t eaton_check_country_info[] = {
|
||||
{ 0, "dummy", eaton_check_country_fun },
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
|
||||
/* Limit nominal output voltage according to HV or LV models */
|
||||
static const char *nominal_output_voltage_fun(double value)
|
||||
{
|
||||
|
@ -330,6 +370,7 @@ static const char *nominal_output_voltage_fun(double value)
|
|||
}
|
||||
break;
|
||||
|
||||
/* line-interactive and online support 200/208 and 220/230/240*/
|
||||
/* HV models */
|
||||
/* 208V */
|
||||
case 200:
|
||||
|
@ -339,6 +380,12 @@ static const char *nominal_output_voltage_fun(double value)
|
|||
case 200:
|
||||
case 208:
|
||||
break;
|
||||
/* 230V */
|
||||
case 220:
|
||||
case 230:
|
||||
case 240:
|
||||
if ((mge_type & 0xFF00) >= MGE_DEFAULT)
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -351,6 +398,16 @@ static const char *nominal_output_voltage_fun(double value)
|
|||
case 240:
|
||||
switch ((long)value)
|
||||
{
|
||||
case 200:
|
||||
case 208:
|
||||
/* line-interactive and online also support 200 / 208 V
|
||||
* So break on offline models */
|
||||
if ((mge_type & 0xFF00) < MGE_DEFAULT)
|
||||
return NULL;
|
||||
/* FIXME: Some European models ("5130 RT 3000") also
|
||||
* support both HV values */
|
||||
if (country_code == COUNTRY_EUROPE_208)
|
||||
break;
|
||||
case 220:
|
||||
case 230:
|
||||
case 240:
|
||||
|
@ -369,6 +426,7 @@ static const char *nominal_output_voltage_fun(double value)
|
|||
}
|
||||
|
||||
static info_lkp_t nominal_output_voltage_info[] = {
|
||||
/* line-interactive, starting with Evolution, support both HV values */
|
||||
/* HV models */
|
||||
/* 208V */
|
||||
{ 200, "200", nominal_output_voltage_fun },
|
||||
|
@ -560,34 +618,34 @@ typedef struct {
|
|||
static models_name_t mge_model_names [] =
|
||||
{
|
||||
/* Ellipse models */
|
||||
{ "ELLIPSE", "300", MGE_DEFAULT, "ellipse 300" },
|
||||
{ "ELLIPSE", "500", MGE_DEFAULT, "ellipse 500" },
|
||||
{ "ELLIPSE", "650", MGE_DEFAULT, "ellipse 650" },
|
||||
{ "ELLIPSE", "800", MGE_DEFAULT, "ellipse 800" },
|
||||
{ "ELLIPSE", "1200", MGE_DEFAULT, "ellipse 1200" },
|
||||
{ "ELLIPSE", "300", MGE_DEFAULT_OFFLINE, "ellipse 300" },
|
||||
{ "ELLIPSE", "500", MGE_DEFAULT_OFFLINE, "ellipse 500" },
|
||||
{ "ELLIPSE", "650", MGE_DEFAULT_OFFLINE, "ellipse 650" },
|
||||
{ "ELLIPSE", "800", MGE_DEFAULT_OFFLINE, "ellipse 800" },
|
||||
{ "ELLIPSE", "1200", MGE_DEFAULT_OFFLINE, "ellipse 1200" },
|
||||
|
||||
/* Ellipse Premium models */
|
||||
{ "ellipse", "PR500", MGE_DEFAULT, "ellipse premium 500" },
|
||||
{ "ellipse", "PR650", MGE_DEFAULT, "ellipse premium 650" },
|
||||
{ "ellipse", "PR800", MGE_DEFAULT, "ellipse premium 800" },
|
||||
{ "ellipse", "PR1200", MGE_DEFAULT, "ellipse premium 1200" },
|
||||
{ "ellipse", "PR500", MGE_DEFAULT_OFFLINE, "ellipse premium 500" },
|
||||
{ "ellipse", "PR650", MGE_DEFAULT_OFFLINE, "ellipse premium 650" },
|
||||
{ "ellipse", "PR800", MGE_DEFAULT_OFFLINE, "ellipse premium 800" },
|
||||
{ "ellipse", "PR1200", MGE_DEFAULT_OFFLINE, "ellipse premium 1200" },
|
||||
|
||||
/* Ellipse "Pro" */
|
||||
{ "ELLIPSE", "600", MGE_DEFAULT, "Ellipse 600" },
|
||||
{ "ELLIPSE", "750", MGE_DEFAULT, "Ellipse 750" },
|
||||
{ "ELLIPSE", "1000", MGE_DEFAULT, "Ellipse 1000" },
|
||||
{ "ELLIPSE", "1500", MGE_DEFAULT, "Ellipse 1500" },
|
||||
{ "ELLIPSE", "600", MGE_DEFAULT_OFFLINE, "Ellipse 600" },
|
||||
{ "ELLIPSE", "750", MGE_DEFAULT_OFFLINE, "Ellipse 750" },
|
||||
{ "ELLIPSE", "1000", MGE_DEFAULT_OFFLINE, "Ellipse 1000" },
|
||||
{ "ELLIPSE", "1500", MGE_DEFAULT_OFFLINE, "Ellipse 1500" },
|
||||
|
||||
/* Ellipse "MAX" (TBR) */
|
||||
/* { "Ellipse MAX", "600", MGE_DEFAULT, NULL }, */
|
||||
/* { "Ellipse MAX", "850", MGE_DEFAULT, NULL }, */
|
||||
/* { "Ellipse MAX", "1100", MGE_DEFAULT, NULL }, */
|
||||
/* { "Ellipse MAX", "1500", MGE_DEFAULT, NULL }, */
|
||||
/* Ellipse MAX */
|
||||
{ "Ellipse MAX", "600", MGE_DEFAULT_OFFLINE, NULL },
|
||||
{ "Ellipse MAX", "850", MGE_DEFAULT_OFFLINE, NULL },
|
||||
{ "Ellipse MAX", "1100", MGE_DEFAULT_OFFLINE, NULL },
|
||||
{ "Ellipse MAX", "1500", MGE_DEFAULT_OFFLINE, NULL },
|
||||
|
||||
/* Protection Center */
|
||||
{ "PROTECTIONCENTER", "420", MGE_DEFAULT, "Protection Center 420" },
|
||||
{ "PROTECTIONCENTER", "500", MGE_DEFAULT, "Protection Center 500" },
|
||||
{ "PROTECTIONCENTER", "675", MGE_DEFAULT, "Protection Center 675" },
|
||||
{ "PROTECTIONCENTER", "420", MGE_DEFAULT_OFFLINE, "Protection Center 420" },
|
||||
{ "PROTECTIONCENTER", "500", MGE_DEFAULT_OFFLINE, "Protection Center 500" },
|
||||
{ "PROTECTIONCENTER", "675", MGE_DEFAULT_OFFLINE, "Protection Center 675" },
|
||||
|
||||
/* Protection Station, supports Eco control */
|
||||
{ "Protection Station", "500", MGE_PEGASUS, NULL },
|
||||
|
@ -600,6 +658,12 @@ static models_name_t mge_model_names [] =
|
|||
{ "Ellipse ECO", "1200", MGE_PEGASUS, NULL },
|
||||
{ "Ellipse ECO", "1600", MGE_PEGASUS, NULL },
|
||||
|
||||
/* 3S, also supports Eco control on some models (AUS 700 and US 750)*/
|
||||
{ "3S", "450", MGE_DEFAULT_OFFLINE, NULL }, /* US only */
|
||||
{ "3S", "550", MGE_DEFAULT_OFFLINE, NULL }, /* US 120V + EU 230V + AUS 240V */
|
||||
{ "3S", "700", MGE_3S, NULL }, /* EU 230V + AUS 240V (w/ eco control) */
|
||||
{ "3S", "750", MGE_3S, NULL }, /* US 120V (w/ eco control) */
|
||||
|
||||
/* Evolution models */
|
||||
{ "Evolution", "500", MGE_DEFAULT, "Pulsar Evolution 500" },
|
||||
{ "Evolution", "800", MGE_DEFAULT, "Pulsar Evolution 800" },
|
||||
|
@ -695,6 +759,10 @@ static models_name_t mge_model_names [] =
|
|||
|
||||
static hid_info_t mge_hid2nut[] =
|
||||
{
|
||||
/* Device collection */
|
||||
/* Just declared to call *hid2info */
|
||||
{ "device.country", ST_FLAG_STRING, 20, "UPS.PowerSummary.Country", NULL, "Europe", HU_FLAG_STATIC, eaton_check_country_info },
|
||||
|
||||
/* Battery page */
|
||||
{ "battery.charge", 0, 0, "UPS.PowerSummary.RemainingCapacity", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.PowerSummary.RemainingCapacityLimitSetting", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
|
@ -704,6 +772,7 @@ static hid_info_t mge_hid2nut[] =
|
|||
{ "battery.runtime", 0, 0, "UPS.PowerSummary.RunTimeToEmpty", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.runtime.elapsed", 0, 0, "UPS.StatisticSystem.Input.[1].Statistic.[1].Time", NULL, "%.0f", HU_FLAG_QUICK_POLL, NULL },
|
||||
{ "battery.runtime.low", ST_FLAG_RW | ST_FLAG_STRING, 10, "UPS.PowerSummary.RemainingTimeLimit", NULL, "%.0f", 0, NULL },
|
||||
{ "battery.temperature", 0, 0, "UPS.BatterySystem.Battery.Temperature", NULL, "%s", 0, kelvin_celsius_conversion },
|
||||
{ "battery.type", 0, 0, "UPS.PowerSummary.iDeviceChemistry", NULL, "%s", HU_FLAG_STATIC, stringid_conversion },
|
||||
{ "battery.voltage", 0, 0, "UPS.BatterySystem.Voltage", NULL, "%.1f", 0, NULL },
|
||||
|
@ -765,6 +834,7 @@ static hid_info_t mge_hid2nut[] =
|
|||
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.Overload", NULL, NULL, 0, overload_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerSummary.PresentStatus.NeedReplacement", NULL, NULL, 0, replacebatt_info },
|
||||
/* FIXME: on Dell, the above requires an "AND" with "UPS.BatterySystem.Battery.Test = 3 " */
|
||||
{ "BOOL", 0, 0, "UPS.LCMSystem.LCMAlarm.[2].PresentStatus.TimerExpired", NULL, NULL, 0, replacebatt_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Buck", NULL, NULL, 0, trim_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.Boost", NULL, NULL, 0, boost_info },
|
||||
{ "BOOL", 0, 0, "UPS.PowerConverter.Input.[1].PresentStatus.VoltageOutOfRange", NULL, NULL, 0, vrange_info },
|
||||
|
@ -867,6 +937,13 @@ static hid_info_t mge_hid2nut[] =
|
|||
* on the master outlet used to automatically power off the slave outlets.
|
||||
* Values: 10, 25 (default) or 60 VA. */
|
||||
{ "outlet.power", ST_FLAG_RW | ST_FLAG_STRING, 6, "UPS.OutletSystem.Outlet.[1].ConfigApparentPower", NULL, "%s", HU_FLAG_SEMI_STATIC | HU_FLAG_ENUM, pegasus_threshold_info },
|
||||
|
||||
{ "outlet.power", 0, 0, "UPS.OutletSystem.Outlet.[1].ApparentPower", NULL, "%.0f", 0, NULL },
|
||||
{ "outlet.realpower", 0, 0, "UPS.OutletSystem.Outlet.[1].ActivePower", NULL, "%.0f", 0, NULL },
|
||||
{ "outlet.current", 0, 0, "UPS.OutletSystem.Outlet.[1].Current", NULL, "%.2f", 0, NULL },
|
||||
{ "outlet.powerfactor", 0, 0, "UPS.OutletSystem.Outlet.[1].PowerFactor", NULL, "%.2f", 0, NULL }, // "%s", 0, mge_powerfactor_conversion },
|
||||
|
||||
/* First outlet */
|
||||
{ "outlet.1.id", 0, 0, "UPS.OutletSystem.Outlet.[2].OutletID", NULL, "%.0f", 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, NULL },
|
||||
{ "outlet.1.switchable", 0, 0, "UPS.OutletSystem.Outlet.[2].PresentStatus.Switchable", NULL, "%s", HU_FLAG_STATIC, yes_no_info },
|
||||
|
@ -876,6 +953,11 @@ static hid_info_t mge_hid2nut[] =
|
|||
{ "outlet.1.autoswitch.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[2].RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "outlet.1.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[2].ShutdownTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "outlet.1.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[2].StartupTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "outlet.1.power", 0, 0, "UPS.OutletSystem.Outlet.[2].ApparentPower", NULL, "%.0f", 0, NULL },
|
||||
{ "outlet.1.realpower", 0, 0, "UPS.OutletSystem.Outlet.[2].ActivePower", NULL, "%.0f", 0, NULL },
|
||||
{ "outlet.1.current", 0, 0, "UPS.OutletSystem.Outlet.[2].Current", NULL, "%.2f", 0, NULL },
|
||||
{ "outlet.1.powerfactor", 0, 0, "UPS.OutletSystem.Outlet.[2].PowerFactor", NULL, "%.2f", 0, NULL }, // "%s", 0, mge_powerfactor_conversion },
|
||||
/* Second outlet */
|
||||
{ "outlet.2.id", 0, 0, "UPS.OutletSystem.Outlet.[3].OutletID", NULL, "%.0f", 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, NULL },
|
||||
/* needed for Pegasus to enable master/slave mode */
|
||||
|
@ -884,6 +966,10 @@ static hid_info_t mge_hid2nut[] =
|
|||
{ "outlet.2.autoswitch.charge.low", ST_FLAG_RW | ST_FLAG_STRING, 3, "UPS.OutletSystem.Outlet.[3].RemainingCapacityLimit", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "outlet.2.delay.shutdown", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[3].ShutdownTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "outlet.2.delay.start", ST_FLAG_RW | ST_FLAG_STRING, 5, "UPS.OutletSystem.Outlet.[3].StartupTimer", NULL, "%.0f", HU_FLAG_SEMI_STATIC, NULL },
|
||||
{ "outlet.2.power", 0, 0, "UPS.OutletSystem.Outlet.[3].ApparentPower", NULL, "%.0f", 0, NULL },
|
||||
{ "outlet.2.realpower", 0, 0, "UPS.OutletSystem.Outlet.[3].ActivePower", NULL, "%.0f", 0, NULL },
|
||||
{ "outlet.2.current", 0, 0, "UPS.OutletSystem.Outlet.[3].Current", NULL, "%.2f", 0, NULL },
|
||||
{ "outlet.2.powerfactor", 0, 0, "UPS.OutletSystem.Outlet.[3].PowerFactor", NULL, "%.2f", 0, NULL }, // "%s", 0, mge_powerfactor_conversion },
|
||||
|
||||
/* instant commands. */
|
||||
/* splited into subset while waiting for extradata support
|
||||
|
|
|
@ -28,8 +28,12 @@
|
|||
|
||||
#define MGE_MIB_VERSION "0.4"
|
||||
|
||||
/* TODO:
|
||||
* - MGE PDU MIB and sysOID (".1.3.6.1.4.1.705.2") */
|
||||
|
||||
/* SNMP OIDs set */
|
||||
#define MGE_BASE_OID ".1.3.6.1.4.1.705.1"
|
||||
#define MGE_SYSOID MGE_BASE_OID
|
||||
#define MGE_OID_MODEL_NAME MGE_BASE_OID ".1.1.0"
|
||||
|
||||
static info_lkp_t mge_lowbatt_info[] = {
|
||||
|
@ -156,4 +160,4 @@ static snmp_info_t mge_mib[] = {
|
|||
{ NULL, 0, 0, NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
mib2nut_info_t mge = { "mge", MGE_MIB_VERSION, "", MGE_OID_MODEL_NAME, mge_mib };
|
||||
mib2nut_info_t mge = { "mge", MGE_MIB_VERSION, "", MGE_OID_MODEL_NAME, mge_mib, MGE_SYSOID };
|
||||
|
|
|
@ -465,7 +465,8 @@ void upsdrv_shutdown(void)
|
|||
{
|
||||
char buf[BUFFLEN];
|
||||
/* static time_t lastcmd = 0; */
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (sdtype == SD_RETURN) {
|
||||
/* enable automatic restart */
|
||||
mge_command(buf, sizeof(buf), "Sx 5");
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
#define NETVISION_MIB_VERSION "0.1"
|
||||
|
||||
#define NETVISION_SYSOID ".1.3.6.1.4.1.4555.1.1.1"
|
||||
|
||||
/* SNMP OIDs set */
|
||||
#define NETVISION_OID_UPS_MIB ".1.3.6.1.4.1.4555.1.1.1.1"
|
||||
#define NETVISION_OID_UPSIDENTMODEL ".1.3.6.1.4.1.4555.1.1.1.1.1.1.0"
|
||||
|
@ -118,4 +120,4 @@ static snmp_info_t netvision_mib[] = {
|
|||
{ NULL, 0, 0, NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
mib2nut_info_t netvision = { "netvision", NETVISION_MIB_VERSION, "", NETVISION_OID_UPSIDENTMODEL, netvision_mib };
|
||||
mib2nut_info_t netvision = { "netvision", NETVISION_MIB_VERSION, "", NETVISION_OID_UPSIDENTMODEL, netvision_mib, NETVISION_SYSOID };
|
||||
|
|
57
drivers/nut-ipmi.h
Normal file
57
drivers/nut-ipmi.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* nut-ipmi.h - Abstract IPMI interface, to allow using different IPMI backends
|
||||
*
|
||||
* Copyright (C) 2011 - Arnaud Quette <arnaud.quette@free.fr>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
PSU_STATUS_UNKNOWN = 1,
|
||||
PSU_PRESENT, /* = status OL */
|
||||
PSU_ABSENT, /* = status stale */
|
||||
PSU_POWER_FAILURE /* = status OFF */
|
||||
} psu_status_t;
|
||||
|
||||
/* Abstract structure to store information */
|
||||
typedef struct IPMIDevice_s {
|
||||
int ipmi_id; /* FRU ID */
|
||||
char* manufacturer; /* Manufacturer Name */
|
||||
char* product; /* Product Name */
|
||||
char* serial; /* Product serial number */
|
||||
char* part; /* Part Number */
|
||||
char* date; /* Manufacturing Date/Time */
|
||||
int overall_capacity; /* realpower.nominal? */
|
||||
int input_minvoltage;
|
||||
int input_maxvoltage;
|
||||
int input_minfreq;
|
||||
int input_maxfreq;
|
||||
int voltage; /* psu.voltage or device.voltage */
|
||||
unsigned int sensors_count; /* number of sensors IDs in sensors_id_list */
|
||||
unsigned int sensors_id_list[20]; /* ID of sensors linked to this FRU */
|
||||
|
||||
/* measurements... */
|
||||
int status; /* values from psu_status_t */
|
||||
double input_voltage;
|
||||
double input_current;
|
||||
double temperature;
|
||||
} IPMIDevice_t;
|
||||
|
||||
/* Generic functions, to implement in the backends */
|
||||
int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev);
|
||||
void nut_ipmi_close(void);
|
||||
int nut_ipmi_monitoring_init();
|
||||
int ipmi_get_sensors_status(IPMIDevice_t *ipmi_dev);
|
240
drivers/nut-ipmipsu.c
Normal file
240
drivers/nut-ipmipsu.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/* nut-ipmipsu.c - Driver for IPMI Power Supply Units (PSU)
|
||||
*
|
||||
* Copyright (C) 2011 - Arnaud Quette <arnaud.quette@free.fr>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* TODO list:
|
||||
* - PSU sensor monitoring (how to find the right one?)
|
||||
* - dump all value at init, so that we can check for other interesting data
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include "nut-ipmi.h"
|
||||
|
||||
#define DRIVER_NAME "IPMI PSU driver"
|
||||
#define DRIVER_VERSION "0.06"
|
||||
|
||||
/* driver description structure */
|
||||
upsdrv_info_t upsdrv_info = {
|
||||
DRIVER_NAME,
|
||||
DRIVER_VERSION,
|
||||
"Arnaud Quette <arnaud.quette@free.fr>\n",
|
||||
DRV_EXPERIMENTAL,
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
/* Note on device.status
|
||||
* OL: present and providing power
|
||||
* OFF: present but not providing power (power cable removed)
|
||||
* stale: not present (PSU removed)
|
||||
* => should we prefer RB, MISSING, ABSENT, ???
|
||||
*/
|
||||
|
||||
/* Abstract structure to allow different IPMI implementation
|
||||
* We currently use FreeIPMI, but OpenIPMI and others are serious
|
||||
* candidates! */
|
||||
IPMIDevice_t ipmi_dev;
|
||||
|
||||
/* Currently used to store FRU ID, but will probably evolve... */
|
||||
int ipmi_id = -1;
|
||||
|
||||
void upsdrv_initinfo(void)
|
||||
{
|
||||
/* try to detect the PSU here - call fatal_with_errno(EXIT_FAILURE, ) if it fails */
|
||||
upsdebugx(1, "upsdrv_initinfo...");
|
||||
|
||||
/* print what we detected during IPMI open */
|
||||
upsdebugx(1, "Detected a PSU: %s/%s",
|
||||
ipmi_dev.manufacturer ? ipmi_dev.manufacturer : "unknown",
|
||||
ipmi_dev.product ? ipmi_dev.product : "unknown");
|
||||
|
||||
dstate_setinfo("driver.version.data", "%s", DRIVER_NAME);
|
||||
dstate_setinfo("driver.version.internal", DRIVER_VERSION);
|
||||
|
||||
dstate_setinfo ("device.type", "psu");
|
||||
|
||||
/* Publish information from the IPMI structure */
|
||||
if (ipmi_dev.manufacturer)
|
||||
dstate_setinfo("device.mfr", "%s", ipmi_dev.manufacturer);
|
||||
|
||||
if (ipmi_dev.product)
|
||||
dstate_setinfo("device.model", "%s", ipmi_dev.product);
|
||||
|
||||
if (ipmi_dev.serial)
|
||||
dstate_setinfo("device.serial", "%s", ipmi_dev.serial);
|
||||
|
||||
if (ipmi_dev.part)
|
||||
dstate_setinfo("device.part", "%s", ipmi_dev.part);
|
||||
|
||||
if (ipmi_dev.date)
|
||||
dstate_setinfo("device.mfr.date", "%s", ipmi_dev.date);
|
||||
|
||||
/* FIXME: move to device.id */
|
||||
dstate_setinfo("ups.id", "%i", ipmi_id);
|
||||
/* FIXME: move to device.realpower.nominal */
|
||||
if (ipmi_dev.overall_capacity != -1)
|
||||
dstate_setinfo("ups.realpower.nominal", "%i", ipmi_dev.overall_capacity);
|
||||
|
||||
if (ipmi_dev.input_minvoltage != -1)
|
||||
dstate_setinfo("input.voltage.minimum", "%i", ipmi_dev.input_minvoltage);
|
||||
|
||||
if (ipmi_dev.input_maxvoltage != -1)
|
||||
dstate_setinfo("input.voltage.maximum", "%i", ipmi_dev.input_maxvoltage);
|
||||
|
||||
if (ipmi_dev.input_minfreq != -1)
|
||||
dstate_setinfo("input.frequency.low", "%i", ipmi_dev.input_minfreq);
|
||||
|
||||
if (ipmi_dev.input_maxfreq != -1)
|
||||
dstate_setinfo("input.frequency.high", "%i", ipmi_dev.input_maxfreq);
|
||||
|
||||
/* FIXME: move to device.voltage */
|
||||
if (ipmi_dev.voltage != -1)
|
||||
dstate_setinfo("ups.voltage", "%i", ipmi_dev.voltage);
|
||||
|
||||
if (nut_ipmi_monitoring_init() != 0)
|
||||
fatalx(EXIT_FAILURE, "Can't initialize IPMI monitoring");
|
||||
|
||||
if (nut_ipmi_get_sensors_status(&ipmi_dev) != 0) {
|
||||
upsdebugx(1, "Error while updating sensors values");
|
||||
dstate_datastale();
|
||||
}
|
||||
else {
|
||||
dstate_dataok();
|
||||
}
|
||||
|
||||
/* upsh.instcmd = instcmd; */
|
||||
}
|
||||
|
||||
void upsdrv_updateinfo(void)
|
||||
{
|
||||
upsdebugx(1, "upsdrv_updateinfo...");
|
||||
|
||||
/* FIXME: implement sensors monitoring */
|
||||
|
||||
if (nut_ipmi_get_sensors_status(&ipmi_dev) != 0) {
|
||||
upsdebugx(1, "Error while updating sensors values");
|
||||
dstate_datastale();
|
||||
}
|
||||
else {
|
||||
dstate_dataok();
|
||||
}
|
||||
|
||||
/*
|
||||
* poll_interval = 2;
|
||||
*/
|
||||
}
|
||||
|
||||
void upsdrv_shutdown(void)
|
||||
{
|
||||
fatalx(EXIT_FAILURE, "shutdown not supported");
|
||||
}
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
/* FIXME: need more params.
|
||||
addvar(VAR_VALUE, "username", "Remote server username");
|
||||
addvar(VAR_VALUE, "password", "Remote server password");
|
||||
addvar(VAR_VALUE, "authtype",
|
||||
"Authentication type to use during lan session activation");
|
||||
addvar(VAR_VALUE, "type",
|
||||
"Type of the device to match ('psu' for \"Power Supply\")");
|
||||
|
||||
addvar(VAR_VALUE, "serial", "Serial number to match a specific device");
|
||||
addvar(VAR_VALUE, "fruid", "FRU identifier to match a specific device");
|
||||
addvar(VAR_VALUE, "sensorid", "Sensor identifier to match a specific device"); */
|
||||
}
|
||||
|
||||
void upsdrv_initups(void)
|
||||
{
|
||||
upsdebugx(1, "upsdrv_initups...");
|
||||
|
||||
/* port can be expressed using:
|
||||
* "id?" for device (FRU) ID 0x?
|
||||
* "psu?" for PSU number ?
|
||||
*/
|
||||
if (!strncmp( device_path, "id", 2))
|
||||
{
|
||||
ipmi_id = atoi(device_path+2);
|
||||
upsdebugx(2, "Device ID 0x%i", ipmi_id);
|
||||
}
|
||||
/* else... <psuX> to select PSU number X */
|
||||
|
||||
/* Clear the interface structure */
|
||||
ipmi_dev.ipmi_id = -1;
|
||||
ipmi_dev.manufacturer = NULL;
|
||||
ipmi_dev.product = NULL;
|
||||
ipmi_dev.serial = NULL;
|
||||
ipmi_dev.part = NULL;
|
||||
ipmi_dev.date = NULL;
|
||||
ipmi_dev.overall_capacity = -1;
|
||||
ipmi_dev.input_minvoltage = -1;
|
||||
ipmi_dev.input_maxvoltage = -1;
|
||||
ipmi_dev.input_minfreq = -1;
|
||||
ipmi_dev.input_maxfreq = -1;
|
||||
ipmi_dev.voltage = -1;
|
||||
ipmi_dev.sensors_count = 0;
|
||||
ipmi_dev.status = -1;
|
||||
ipmi_dev.input_voltage = -1;
|
||||
ipmi_dev.input_current = -1;
|
||||
ipmi_dev.temperature = -1;
|
||||
|
||||
/* Open IPMI using the above */
|
||||
nut_ipmi_open(ipmi_id, &ipmi_dev);
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
void upsdrv_cleanup(void)
|
||||
{
|
||||
upsdebugx(1, "upsdrv_cleanup...");
|
||||
nut_ipmi_close();
|
||||
}
|
935
drivers/nut-libfreeipmi.c
Normal file
935
drivers/nut-libfreeipmi.c
Normal file
|
@ -0,0 +1,935 @@
|
|||
/* nut-libfreeipmi.c - NUT IPMI backend, using FreeIPMI
|
||||
*
|
||||
* Copyright (C)
|
||||
* 2011 - Arnaud Quette <arnaud.quette@free.fr>
|
||||
* 2011 - Albert Chu <chu11@llnl.gov>
|
||||
*
|
||||
* Based on the sample codes 'ipmi-fru-example.c', 'frulib.c' and
|
||||
* 'ipmimonitoring-sensors.c', from FreeIPMI
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <freeipmi/freeipmi.h>
|
||||
#include <ipmi_monitoring.h>
|
||||
#include <ipmi_monitoring_bitmasks.h>
|
||||
#include "common.h"
|
||||
#include "nut-ipmi.h"
|
||||
#include "dstate.h"
|
||||
|
||||
/* FreeIPMI defines */
|
||||
#define IPMI_FRU_STR_BUFLEN 1024
|
||||
/* haven't seen a motherboard with more than 2-3 so far,
|
||||
* 64 should be more than enough */
|
||||
#define IPMI_FRU_CUSTOM_FIELDS 64
|
||||
|
||||
/* FreeIPMI contexts and configuration*/
|
||||
ipmi_ctx_t ipmi_ctx = NULL;
|
||||
ipmi_fru_parse_ctx_t fru_parse_ctx = NULL;
|
||||
ipmi_sdr_cache_ctx_t sdr_cache_ctx = NULL;
|
||||
ipmi_sdr_parse_ctx_t sdr_parse_ctx = NULL;
|
||||
ipmi_monitoring_ctx_t mon_ctx = NULL;
|
||||
struct ipmi_monitoring_ipmi_config ipmi_config;
|
||||
|
||||
/* FIXME: freeipmi auto selects a cache based on the hostname you are
|
||||
* connecting too, but this is probably fine for you
|
||||
*/
|
||||
#define CACHE_LOCATION "/tmp/sdrcache"
|
||||
|
||||
/* Support functions */
|
||||
static const char* libfreeipmi_getfield (uint8_t language_code,
|
||||
ipmi_fru_parse_field_t *field);
|
||||
|
||||
static void libfreeipmi_cleanup();
|
||||
|
||||
static int libfreeipmi_get_psu_info (const void *areabuf,
|
||||
uint8_t area_length, IPMIDevice_t *ipmi_dev);
|
||||
|
||||
static int libfreeipmi_get_board_info (const void *areabuf,
|
||||
uint8_t area_length, IPMIDevice_t *ipmi_dev);
|
||||
|
||||
static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev);
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* Implementation
|
||||
******************************************************************************/
|
||||
int nut_ipmi_open(int ipmi_id, IPMIDevice_t *ipmi_dev)
|
||||
{
|
||||
int ret = -1;
|
||||
uint8_t areabuf[IPMI_FRU_PARSE_AREA_SIZE_MAX+1];
|
||||
unsigned int area_type = 0;
|
||||
unsigned int area_length = 0;
|
||||
|
||||
upsdebugx(1, "nut-libfreeipmi: nutipmi_open()...");
|
||||
|
||||
/* Initialize the FreeIPMI library. */
|
||||
if (!(ipmi_ctx = ipmi_ctx_create ()))
|
||||
{
|
||||
/* we have to force cleanup, since exit handler is not yet installed */
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_ctx_create");
|
||||
}
|
||||
|
||||
if ((ret = ipmi_ctx_find_inband (ipmi_ctx,
|
||||
NULL,
|
||||
0, /* don't disable auto-probe */
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0, /* workaround flags, none by default */
|
||||
0 /* flags */
|
||||
)) < 0)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatalx(EXIT_FAILURE, "ipmi_ctx_find_inband: %s",
|
||||
ipmi_ctx_errormsg (ipmi_ctx));
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatalx(EXIT_FAILURE, "could not find inband device");
|
||||
}
|
||||
|
||||
upsdebugx(1, "FreeIPMI initialized...");
|
||||
|
||||
/* Parse FRU information */
|
||||
if (!(fru_parse_ctx = ipmi_fru_parse_ctx_create (ipmi_ctx)))
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_fru_parse_ctx_create()");
|
||||
}
|
||||
|
||||
/* lots of motherboards calculate checksums incorrectly */
|
||||
if (ipmi_fru_parse_ctx_set_flags (fru_parse_ctx, IPMI_FRU_PARSE_FLAGS_SKIP_CHECKSUM_CHECKS) < 0)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatalx(EXIT_FAILURE, "ipmi_fru_parse_ctx_set_flags: %s\n",
|
||||
ipmi_fru_parse_ctx_strerror (ipmi_fru_parse_ctx_errnum (fru_parse_ctx)));
|
||||
}
|
||||
|
||||
/* Now open the requested (local) PSU */
|
||||
if (ipmi_fru_parse_open_device_id (fru_parse_ctx, ipmi_id) < 0)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatalx(EXIT_FAILURE, "ipmi_fru_parse_open_device_id: %s\n",
|
||||
ipmi_fru_parse_ctx_errormsg (fru_parse_ctx));
|
||||
}
|
||||
|
||||
/* Set IPMI identifier */
|
||||
ipmi_dev->ipmi_id = ipmi_id;
|
||||
|
||||
do
|
||||
{
|
||||
/* clear fields */
|
||||
area_type = 0;
|
||||
area_length = 0;
|
||||
memset (areabuf, '\0', IPMI_FRU_PARSE_AREA_SIZE_MAX + 1);
|
||||
|
||||
/* parse FRU buffer */
|
||||
if (ipmi_fru_parse_read_data_area (fru_parse_ctx,
|
||||
&area_type,
|
||||
&area_length,
|
||||
areabuf,
|
||||
IPMI_FRU_PARSE_AREA_SIZE_MAX) < 0)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE,
|
||||
"ipmi_fru_parse_open_device_id: %s\n",
|
||||
ipmi_fru_parse_ctx_errormsg (fru_parse_ctx));
|
||||
}
|
||||
|
||||
if (area_length)
|
||||
{
|
||||
switch (area_type)
|
||||
{
|
||||
/* get generic board information */
|
||||
case IPMI_FRU_PARSE_AREA_TYPE_BOARD_INFO_AREA:
|
||||
|
||||
if(libfreeipmi_get_board_info (areabuf, area_length,
|
||||
ipmi_dev) < 0)
|
||||
{
|
||||
upsdebugx(1, "Can't retrieve board information");
|
||||
}
|
||||
break;
|
||||
/* get specific PSU information */
|
||||
case IPMI_FRU_PARSE_AREA_TYPE_MULTIRECORD_POWER_SUPPLY_INFORMATION:
|
||||
|
||||
if(libfreeipmi_get_psu_info (areabuf, area_length, ipmi_dev) < 0)
|
||||
{
|
||||
upsdebugx(1, "Can't retrieve PSU information");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
upsdebugx (5, "FRU: discarding FRU Area Type Read: %02Xh", area_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((ret = ipmi_fru_parse_next (fru_parse_ctx)) == 1);
|
||||
|
||||
/* check for errors */
|
||||
if (ret < 0) {
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_fru_parse_next: %s",
|
||||
ipmi_fru_parse_ctx_errormsg (fru_parse_ctx));
|
||||
}
|
||||
else {
|
||||
/* Get all related sensors information */
|
||||
libfreeipmi_get_sensors_info (ipmi_dev);
|
||||
}
|
||||
|
||||
/* cleanup context */
|
||||
libfreeipmi_cleanup();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void nut_ipmi_close(void)
|
||||
{
|
||||
upsdebugx(1, "nutipmi_close...");
|
||||
|
||||
libfreeipmi_cleanup();
|
||||
}
|
||||
|
||||
static const char* libfreeipmi_getfield (uint8_t language_code,
|
||||
ipmi_fru_parse_field_t *field)
|
||||
{
|
||||
static char strbuf[IPMI_FRU_PARSE_AREA_STRING_MAX + 1];
|
||||
unsigned int strbuflen = IPMI_FRU_PARSE_AREA_STRING_MAX;
|
||||
|
||||
if (!field->type_length_field_length)
|
||||
return NULL;
|
||||
|
||||
memset (strbuf, '\0', IPMI_FRU_PARSE_AREA_STRING_MAX + 1);
|
||||
|
||||
if (ipmi_fru_parse_type_length_field_to_string (fru_parse_ctx,
|
||||
field->type_length_field,
|
||||
field->type_length_field_length,
|
||||
language_code,
|
||||
strbuf,
|
||||
&strbuflen) < 0)
|
||||
{
|
||||
upsdebugx (2, "ipmi_fru_parse_type_length_field_to_string: %s",
|
||||
ipmi_fru_parse_ctx_errormsg (fru_parse_ctx));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strbuflen)
|
||||
return strbuf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get voltage value from the IPMI voltage code */
|
||||
static float libfreeipmi_get_voltage (uint8_t voltage_code)
|
||||
{
|
||||
if (voltage_code == IPMI_FRU_VOLTAGE_12V)
|
||||
return 12;
|
||||
else if (voltage_code == IPMI_FRU_VOLTAGE_MINUS12V)
|
||||
return -12;
|
||||
else if (voltage_code == IPMI_FRU_VOLTAGE_5V)
|
||||
return 5;
|
||||
else if (voltage_code == IPMI_FRU_VOLTAGE_3_3V)
|
||||
return 3.3;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cleanup IPMI contexts */
|
||||
static void libfreeipmi_cleanup()
|
||||
{
|
||||
/* cleanup */
|
||||
if (fru_parse_ctx) {
|
||||
ipmi_fru_parse_close_device_id (fru_parse_ctx);
|
||||
ipmi_fru_parse_ctx_destroy (fru_parse_ctx);
|
||||
}
|
||||
|
||||
if (sdr_cache_ctx) {
|
||||
ipmi_sdr_cache_ctx_destroy (sdr_cache_ctx);
|
||||
}
|
||||
|
||||
if (sdr_parse_ctx) {
|
||||
ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx);
|
||||
}
|
||||
|
||||
if (ipmi_ctx) {
|
||||
ipmi_ctx_close (ipmi_ctx);
|
||||
ipmi_ctx_destroy (ipmi_ctx);
|
||||
}
|
||||
|
||||
if (mon_ctx) {
|
||||
ipmi_monitoring_ctx_destroy (mon_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get generic board information (manufacturer and model names, serial, ...)
|
||||
* from IPMI FRU */
|
||||
static int libfreeipmi_get_psu_info (const void *areabuf,
|
||||
uint8_t area_length,
|
||||
IPMIDevice_t *ipmi_dev)
|
||||
{
|
||||
/* FIXME: directly use ipmi_dev fields */
|
||||
unsigned int overall_capacity;
|
||||
unsigned int low_end_input_voltage_range_1;
|
||||
unsigned int high_end_input_voltage_range_1;
|
||||
unsigned int low_end_input_frequency_range;
|
||||
unsigned int high_end_input_frequency_range;
|
||||
unsigned int voltage_1;
|
||||
|
||||
/* FIXME: check for the interest and capability to use these data */
|
||||
unsigned int peak_va;
|
||||
unsigned int inrush_current;
|
||||
unsigned int inrush_interval;
|
||||
unsigned int low_end_input_voltage_range_2;
|
||||
unsigned int high_end_input_voltage_range_2;
|
||||
unsigned int ac_dropout_tolerance;
|
||||
unsigned int predictive_fail_support;
|
||||
unsigned int power_factor_correction;
|
||||
unsigned int autoswitch;
|
||||
unsigned int hot_swap_support;
|
||||
unsigned int tachometer_pulses_per_rotation_predictive_fail_polarity;
|
||||
unsigned int peak_capacity;
|
||||
unsigned int hold_up_time;
|
||||
unsigned int voltage_2;
|
||||
unsigned int total_combined_wattage;
|
||||
unsigned int predictive_fail_tachometer_lower_threshold;
|
||||
|
||||
upsdebugx(1, "entering libfreeipmi_get_psu_info()");
|
||||
|
||||
if (ipmi_fru_parse_multirecord_power_supply_information (fru_parse_ctx,
|
||||
areabuf,
|
||||
area_length,
|
||||
&overall_capacity,
|
||||
&peak_va,
|
||||
&inrush_current,
|
||||
&inrush_interval,
|
||||
&low_end_input_voltage_range_1,
|
||||
&high_end_input_voltage_range_1,
|
||||
&low_end_input_voltage_range_2,
|
||||
&high_end_input_voltage_range_2,
|
||||
&low_end_input_frequency_range,
|
||||
&high_end_input_frequency_range,
|
||||
&ac_dropout_tolerance,
|
||||
&predictive_fail_support,
|
||||
&power_factor_correction,
|
||||
&autoswitch,
|
||||
&hot_swap_support,
|
||||
&tachometer_pulses_per_rotation_predictive_fail_polarity,
|
||||
&peak_capacity,
|
||||
&hold_up_time,
|
||||
&voltage_1,
|
||||
&voltage_2,
|
||||
&total_combined_wattage,
|
||||
&predictive_fail_tachometer_lower_threshold) < 0)
|
||||
{
|
||||
fatalx(EXIT_FAILURE, "ipmi_fru_parse_multirecord_power_supply_information: %s",
|
||||
ipmi_fru_parse_ctx_errormsg (fru_parse_ctx));
|
||||
}
|
||||
|
||||
ipmi_dev->overall_capacity = overall_capacity;
|
||||
|
||||
/* Voltages are in mV! */
|
||||
ipmi_dev->input_minvoltage = low_end_input_voltage_range_1 / 1000;
|
||||
ipmi_dev->input_maxvoltage = high_end_input_voltage_range_1 / 1000;
|
||||
|
||||
ipmi_dev->input_minfreq = low_end_input_frequency_range;
|
||||
ipmi_dev->input_maxfreq = high_end_input_frequency_range;
|
||||
|
||||
ipmi_dev->voltage = libfreeipmi_get_voltage(voltage_1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get specific PSU information from IPMI FRU */
|
||||
static int libfreeipmi_get_board_info (const void *areabuf,
|
||||
uint8_t area_length, IPMIDevice_t *ipmi_dev)
|
||||
{
|
||||
uint8_t language_code;
|
||||
uint32_t mfg_date_time;
|
||||
ipmi_fru_parse_field_t board_manufacturer;
|
||||
ipmi_fru_parse_field_t board_product_name;
|
||||
ipmi_fru_parse_field_t board_serial_number;
|
||||
ipmi_fru_parse_field_t board_part_number;
|
||||
ipmi_fru_parse_field_t board_fru_file_id;
|
||||
ipmi_fru_parse_field_t board_custom_fields[IPMI_FRU_CUSTOM_FIELDS];
|
||||
const char *string = NULL;
|
||||
time_t timetmp;
|
||||
struct tm mfg_date_time_tm;
|
||||
char mfg_date_time_buf[IPMI_FRU_STR_BUFLEN + 1];
|
||||
|
||||
upsdebugx(1, "entering libfreeipmi_get_board_info()");
|
||||
|
||||
/* clear fields */
|
||||
memset (&board_manufacturer, '\0', sizeof (ipmi_fru_parse_field_t));
|
||||
memset (&board_product_name, '\0', sizeof (ipmi_fru_parse_field_t));
|
||||
memset (&board_serial_number, '\0', sizeof (ipmi_fru_parse_field_t));
|
||||
memset (&board_fru_file_id, '\0', sizeof (ipmi_fru_parse_field_t));
|
||||
memset (&board_custom_fields[0], '\0',
|
||||
sizeof (ipmi_fru_parse_field_t) * IPMI_FRU_CUSTOM_FIELDS);
|
||||
|
||||
/* parse FRU buffer */
|
||||
if (ipmi_fru_parse_board_info_area (fru_parse_ctx,
|
||||
areabuf,
|
||||
area_length,
|
||||
&language_code,
|
||||
&mfg_date_time,
|
||||
&board_manufacturer,
|
||||
&board_product_name,
|
||||
&board_serial_number,
|
||||
&board_part_number,
|
||||
&board_fru_file_id,
|
||||
board_custom_fields,
|
||||
IPMI_FRU_CUSTOM_FIELDS) < 0)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatalx(EXIT_FAILURE, "ipmi_fru_parse_board_info_area: %s",
|
||||
ipmi_fru_parse_ctx_errormsg (fru_parse_ctx));
|
||||
}
|
||||
|
||||
|
||||
if (IPMI_FRU_LANGUAGE_CODE_VALID (language_code)) {
|
||||
upsdebugx (5, "FRU Board Language: %s", ipmi_fru_language_codes[language_code]);
|
||||
}
|
||||
else {
|
||||
upsdebugx (5, "FRU Board Language Code: %02Xh", language_code);
|
||||
}
|
||||
|
||||
/* Posix says individual calls need not clear/set all portions of
|
||||
* 'struct tm', thus passing 'struct tm' between functions could
|
||||
* have issues. So we need to memset */
|
||||
memset (&mfg_date_time_tm, '\0', sizeof (struct tm));
|
||||
timetmp = mfg_date_time;
|
||||
localtime_r (&timetmp, &mfg_date_time_tm);
|
||||
memset (mfg_date_time_buf, '\0', IPMI_FRU_STR_BUFLEN + 1);
|
||||
strftime (mfg_date_time_buf, IPMI_FRU_STR_BUFLEN, "%D - %T", &mfg_date_time_tm);
|
||||
|
||||
/* Store values */
|
||||
ipmi_dev->date = xstrdup(mfg_date_time_buf);
|
||||
upsdebugx(2, "FRU Board Manufacturing Date/Time: %s", ipmi_dev->date);
|
||||
|
||||
if ((string = libfreeipmi_getfield (language_code, &board_manufacturer)) != NULL)
|
||||
ipmi_dev->manufacturer = xstrdup(string);
|
||||
else
|
||||
ipmi_dev->manufacturer = xstrdup("Generic IPMI manufacturer");
|
||||
|
||||
if ((string = libfreeipmi_getfield (language_code, &board_product_name)) != NULL)
|
||||
ipmi_dev->product = xstrdup(string);
|
||||
else
|
||||
ipmi_dev->product = xstrdup("Generic PSU");
|
||||
|
||||
if ((string = libfreeipmi_getfield (language_code, &board_serial_number)) != NULL)
|
||||
ipmi_dev->serial = xstrdup(string);
|
||||
else
|
||||
ipmi_dev->serial = NULL;
|
||||
|
||||
if ((string = libfreeipmi_getfield (language_code, &board_part_number)) != NULL)
|
||||
ipmi_dev->part = xstrdup(string);
|
||||
else
|
||||
ipmi_dev->part = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* Get the sensors list & values, specific to the given FRU ID
|
||||
* Return -1 on error, or the number of sensors found otherwise */
|
||||
static int libfreeipmi_get_sensors_info (IPMIDevice_t *ipmi_dev)
|
||||
{
|
||||
uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH];
|
||||
uint8_t record_type, logical_physical_fru_device, logical_fru_device_device_slave_address;
|
||||
uint8_t tmp_entity_id, tmp_entity_instance;
|
||||
int sdr_record_len;
|
||||
uint16_t record_count;
|
||||
int found_device_id = 0;
|
||||
uint16_t record_id;
|
||||
uint8_t entity_id, entity_instance;
|
||||
int i;
|
||||
|
||||
if (ipmi_ctx == NULL)
|
||||
return (-1);
|
||||
|
||||
/* Clear the sensors list */
|
||||
ipmi_dev->sensors_count = 0;
|
||||
memset(ipmi_dev->sensors_id_list, 0, sizeof(ipmi_dev->sensors_id_list));
|
||||
|
||||
if (!(sdr_cache_ctx = ipmi_sdr_cache_ctx_create ()))
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_ctx_create()");
|
||||
}
|
||||
|
||||
if (!(sdr_parse_ctx = ipmi_sdr_parse_ctx_create ()))
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_parse_ctx_create()");
|
||||
}
|
||||
|
||||
if (ipmi_sdr_cache_open (sdr_cache_ctx, ipmi_ctx, CACHE_LOCATION) < 0)
|
||||
{
|
||||
if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) != IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
}
|
||||
}
|
||||
|
||||
if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) == IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
|
||||
{
|
||||
if (ipmi_sdr_cache_create (sdr_cache_ctx,
|
||||
ipmi_ctx, CACHE_LOCATION,
|
||||
IPMI_SDR_CACHE_CREATE_FLAGS_DEFAULT,
|
||||
IPMI_SDR_CACHE_VALIDATION_FLAGS_DEFAULT,
|
||||
NULL, NULL) < 0)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_create: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
}
|
||||
|
||||
if (ipmi_sdr_cache_open (sdr_cache_ctx,
|
||||
ipmi_ctx, CACHE_LOCATION) < 0)
|
||||
{
|
||||
if (ipmi_sdr_cache_ctx_errnum (sdr_cache_ctx) != IPMI_SDR_CACHE_ERR_CACHE_READ_CACHE_DOES_NOT_EXIST)
|
||||
{
|
||||
libfreeipmi_cleanup();
|
||||
fatal_with_errno(EXIT_FAILURE, "ipmi_sdr_cache_open: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ipmi_sdr_cache_record_count (sdr_cache_ctx, &record_count) < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"ipmi_sdr_cache_record_count: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_cache_ctx))
|
||||
{
|
||||
memset (sdr_record, '\0', IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH);
|
||||
if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_cache_ctx,
|
||||
sdr_record,
|
||||
IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH)) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_cache_record_read: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ipmi_sdr_parse_record_id_and_type (sdr_parse_ctx,
|
||||
sdr_record,
|
||||
sdr_record_len,
|
||||
NULL,
|
||||
&record_type) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s",
|
||||
ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (record_type != IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD)
|
||||
continue;
|
||||
|
||||
if (ipmi_sdr_parse_fru_device_locator_parameters (sdr_parse_ctx,
|
||||
sdr_record,
|
||||
sdr_record_len,
|
||||
NULL,
|
||||
&logical_fru_device_device_slave_address,
|
||||
NULL,
|
||||
NULL,
|
||||
&logical_physical_fru_device,
|
||||
NULL) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_parse_fru_device_locator_parameters: %s",
|
||||
ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (logical_physical_fru_device
|
||||
&& logical_fru_device_device_slave_address == ipmi_dev->ipmi_id)
|
||||
{
|
||||
found_device_id++;
|
||||
|
||||
if (ipmi_sdr_parse_fru_entity_id_and_instance (sdr_parse_ctx,
|
||||
sdr_record,
|
||||
sdr_record_len,
|
||||
&entity_id,
|
||||
&entity_instance) < 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"ipmi_sdr_parse_fru_entity_id_and_instance: %s",
|
||||
ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_device_id)
|
||||
{
|
||||
fprintf (stderr, "Couldn't find device id %d", ipmi_dev->ipmi_id);
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
upsdebugx(1, "Found device id %d", ipmi_dev->ipmi_id);
|
||||
|
||||
if (ipmi_sdr_cache_first (sdr_cache_ctx) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_cache_first: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < record_count; i++, ipmi_sdr_cache_next (sdr_cache_ctx))
|
||||
{
|
||||
/* uint8_t sdr_record[IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH];
|
||||
uint8_t record_type, tmp_entity_id, tmp_entity_instance;
|
||||
int sdr_record_len; */
|
||||
|
||||
memset (sdr_record, '\0', IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH);
|
||||
if ((sdr_record_len = ipmi_sdr_cache_record_read (sdr_cache_ctx,
|
||||
sdr_record,
|
||||
IPMI_SDR_CACHE_MAX_SDR_RECORD_LENGTH)) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_cache_record_read: %s",
|
||||
ipmi_sdr_cache_ctx_errormsg (sdr_cache_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ipmi_sdr_parse_record_id_and_type (sdr_parse_ctx,
|
||||
sdr_record,
|
||||
sdr_record_len,
|
||||
&record_id,
|
||||
&record_type) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_parse_record_id_and_type: %s",
|
||||
ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
upsdebugx (5, "Checking record %i (/%i)", record_id, record_count);
|
||||
|
||||
if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
|
||||
&& record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
|
||||
&& record_type != IPMI_SDR_FORMAT_EVENT_ONLY_RECORD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ipmi_sdr_parse_entity_id_instance_type (sdr_parse_ctx,
|
||||
sdr_record,
|
||||
sdr_record_len,
|
||||
&tmp_entity_id,
|
||||
&tmp_entity_instance,
|
||||
NULL) < 0)
|
||||
{
|
||||
fprintf (stderr, "ipmi_sdr_parse_entity_instance_type: %s",
|
||||
ipmi_sdr_parse_ctx_errormsg (sdr_parse_ctx));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (tmp_entity_id == entity_id
|
||||
&& tmp_entity_instance == entity_instance)
|
||||
{
|
||||
upsdebugx (1, "Found record id = %u for device id %u",
|
||||
record_id, ipmi_dev->ipmi_id);
|
||||
|
||||
/* Add it to the tracked list */
|
||||
ipmi_dev->sensors_id_list[ipmi_dev->sensors_count] = record_id;
|
||||
ipmi_dev->sensors_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cleanup:
|
||||
/* Cleanup */
|
||||
if (sdr_cache_ctx) {
|
||||
ipmi_sdr_cache_ctx_destroy (sdr_cache_ctx);
|
||||
}
|
||||
|
||||
if (sdr_parse_ctx) {
|
||||
ipmi_sdr_parse_ctx_destroy (sdr_parse_ctx);
|
||||
}
|
||||
|
||||
return ipmi_dev->sensors_count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=> Nominal conditions
|
||||
|
||||
|
||||
Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String
|
||||
52, Presence, 84, Entity Presence, Nominal, N/A, N/A, 6Fh, 1h, 'Entity Present'
|
||||
57, Status, 100, Power Supply, Nominal, N/A, N/A, 6Fh, 1h, 'Presence detected'
|
||||
116, Current, 148, Current, Nominal, 0.20, A, 1h, C0h, 'OK'
|
||||
118, Voltage, 150, Voltage, Nominal, 236.00, V, 1h, C0h, 'OK'
|
||||
|
||||
=> Power failure conditions
|
||||
|
||||
Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String
|
||||
52, Presence, 84, Entity Presence, Nominal, N/A, N/A, 6Fh, 1h, 'Entity Present'
|
||||
57, Status, 100, Power Supply, Critical, N/A, N/A, 6Fh, 9h, 'Presence detected' 'Power Supply input lost (AC/DC)'
|
||||
|
||||
=> PSU removed
|
||||
|
||||
Record ID, Sensor Name, Sensor Number, Sensor Type, Sensor State, Sensor Reading, Sensor Units, Sensor Event/Reading Type Code, Sensor Event Bitmask, Sensor Event String
|
||||
52, Presence, 84, Entity Presence, Critical, N/A, N/A, 6Fh, 2h, 'Entity Absent'
|
||||
57, Status, 100, Power Supply, Critical, N/A, N/A, 6Fh, 8h, 'Power Supply input lost (AC/DC)'
|
||||
|
||||
*/
|
||||
|
||||
int nut_ipmi_monitoring_init()
|
||||
{
|
||||
int errnum;
|
||||
|
||||
if (ipmi_monitoring_init (0, &errnum) < 0) {
|
||||
upsdebugx (1, "ipmi_monitoring_init() error: %s", ipmi_monitoring_ctx_strerror (errnum));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(mon_ctx = ipmi_monitoring_ctx_create ())) {
|
||||
upsdebugx (1, "ipmi_monitoring_ctx_create() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* FIXME: replace "/tmp" by a proper place, using mkdtemp() or similar */
|
||||
if (ipmi_monitoring_ctx_sdr_cache_directory (mon_ctx, "/tmp") < 0) {
|
||||
upsdebugx (1, "ipmi_monitoring_ctx_sdr_cache_directory() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ipmi_monitoring_ctx_sensor_config_file (mon_ctx, NULL) < 0) {
|
||||
upsdebugx (1, "ipmi_monitoring_ctx_sensor_config_file() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nut_ipmi_get_sensors_status(IPMIDevice_t *ipmi_dev)
|
||||
{
|
||||
/* It seems we don't need more! */
|
||||
unsigned int sensor_reading_flags = IPMI_MONITORING_SENSOR_READING_FLAGS_IGNORE_NON_INTERPRETABLE_SENSORS;
|
||||
int sensor_count, i, str_count;
|
||||
int psu_status = PSU_STATUS_UNKNOWN;
|
||||
int retval = 0;
|
||||
|
||||
if (mon_ctx == NULL) {
|
||||
upsdebugx (1, "Monitoring context not initialized!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Monitor only the list of sensors found previously */
|
||||
if ((sensor_count = ipmi_monitoring_sensor_readings_by_record_id (mon_ctx,
|
||||
NULL, /* hostname is NULL for In-band communication */
|
||||
NULL, /* FIXME: needed? ipmi_config */
|
||||
sensor_reading_flags,
|
||||
ipmi_dev->sensors_id_list,
|
||||
ipmi_dev->sensors_count,
|
||||
NULL,
|
||||
NULL)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_readings_by_record_id() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < sensor_count; i++, ipmi_monitoring_sensor_iterator_next (mon_ctx))
|
||||
{
|
||||
int record_id, sensor_type;
|
||||
int sensor_bitmask_type = -1;
|
||||
/* int sensor_reading_type, sensor_state; */
|
||||
char **sensor_bitmask_strings = NULL;
|
||||
void *sensor_reading = NULL;
|
||||
|
||||
if ((record_id = ipmi_monitoring_sensor_read_record_id (mon_ctx)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_read_record_id() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sensor_type = ipmi_monitoring_sensor_read_sensor_type (mon_ctx)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_type() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* should we consider this for ALARM?
|
||||
* IPMI_MONITORING_STATE_NOMINAL
|
||||
* IPMI_MONITORING_STATE_WARNING
|
||||
* IPMI_MONITORING_STATE_CRITICAL
|
||||
* if ((sensor_state = ipmi_monitoring_sensor_read_sensor_state (mon_ctx)) < 0)
|
||||
* ... */
|
||||
|
||||
if ((sensor_reading = ipmi_monitoring_sensor_read_sensor_reading (mon_ctx)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_reading() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
}
|
||||
|
||||
/* This can be needed to interpret sensor_reading format!
|
||||
if ((sensor_reading_type = ipmi_monitoring_sensor_read_sensor_reading_type (ctx)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_reading_type() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
} */
|
||||
|
||||
if ((sensor_bitmask_type = ipmi_monitoring_sensor_read_sensor_bitmask_type (mon_ctx)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_bitmask_type() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((sensor_bitmask_strings = ipmi_monitoring_sensor_read_sensor_bitmask_strings (mon_ctx)) < 0)
|
||||
{
|
||||
upsdebugx (1, "ipmi_monitoring_sensor_read_sensor_bitmask_strings() error: %s",
|
||||
ipmi_monitoring_ctx_errormsg (mon_ctx));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Only the few possibly interesting sensors are considered */
|
||||
switch (sensor_type)
|
||||
{
|
||||
case IPMI_MONITORING_SENSOR_TYPE_TEMPERATURE:
|
||||
ipmi_dev->temperature = *((double *)sensor_reading);
|
||||
upsdebugx (3, "Temperature: %.2f", *((double *)sensor_reading));
|
||||
dstate_setinfo("ambient.temperature", "%.2f", *((double *)sensor_reading));
|
||||
break;
|
||||
case IPMI_MONITORING_SENSOR_TYPE_VOLTAGE:
|
||||
ipmi_dev->voltage = *((double *)sensor_reading);
|
||||
upsdebugx (3, "Voltage: %.2f", *((double *)sensor_reading));
|
||||
dstate_setinfo("input.voltage", "%.2f", *((double *)sensor_reading));
|
||||
break;
|
||||
case IPMI_MONITORING_SENSOR_TYPE_CURRENT:
|
||||
ipmi_dev->input_current = *((double *)sensor_reading);
|
||||
upsdebugx (3, "Current: %.2f", *((double *)sensor_reading));
|
||||
dstate_setinfo("input.current", "%.2f", *((double *)sensor_reading));
|
||||
break;
|
||||
|
||||
case IPMI_MONITORING_SENSOR_TYPE_POWER_SUPPLY:
|
||||
/* Possible values:
|
||||
* 'Presence detected'
|
||||
* 'Power Supply input lost (AC/DC)' => maps to status:OFF */
|
||||
upsdebugx (3, "Power Supply: status string");
|
||||
if (sensor_bitmask_type == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN) {
|
||||
upsdebugx(3, "No status string");
|
||||
}
|
||||
str_count = 0;
|
||||
while (sensor_bitmask_strings[str_count])
|
||||
{
|
||||
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
|
||||
if (!strncmp("Power Supply input lost (AC/DC)",
|
||||
sensor_bitmask_strings[str_count],
|
||||
strlen("Power Supply input lost (AC/DC)"))) {
|
||||
/* Don't override PSU absence! */
|
||||
if (psu_status != PSU_ABSENT) {
|
||||
psu_status = PSU_POWER_FAILURE; /* = status OFF */
|
||||
}
|
||||
}
|
||||
str_count++;
|
||||
}
|
||||
break;
|
||||
case IPMI_MONITORING_SENSOR_TYPE_ENTITY_PRESENCE:
|
||||
/* Possible values:
|
||||
* 'Entity Present' => maps to status:OL
|
||||
* 'Entity Absent' (PSU has been removed!) => declare staleness */
|
||||
upsdebugx (3, "Entity Presence: status string");
|
||||
if (sensor_bitmask_type == IPMI_MONITORING_SENSOR_BITMASK_TYPE_UNKNOWN) {
|
||||
upsdebugx(3, "No status string");
|
||||
}
|
||||
str_count = 0;
|
||||
while (sensor_bitmask_strings[str_count])
|
||||
{
|
||||
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
|
||||
if (!strncmp("Entity Present",
|
||||
sensor_bitmask_strings[str_count],
|
||||
strlen("Entity Present"))) {
|
||||
psu_status = PSU_PRESENT;
|
||||
}
|
||||
else if (!strncmp("Entity Absent",
|
||||
sensor_bitmask_strings[str_count],
|
||||
strlen("Entity Absent"))) {
|
||||
psu_status = PSU_ABSENT;
|
||||
}
|
||||
str_count++;
|
||||
}
|
||||
break;
|
||||
/* Not sure of the values of these, so get as much as possible... */
|
||||
case IPMI_MONITORING_SENSOR_TYPE_POWER_UNIT:
|
||||
upsdebugx (3, "Power Unit: status string");
|
||||
str_count = 0;
|
||||
while (sensor_bitmask_strings[str_count])
|
||||
{
|
||||
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
|
||||
str_count++;
|
||||
}
|
||||
break;
|
||||
case IPMI_MONITORING_SENSOR_TYPE_SYSTEM_ACPI_POWER_STATE:
|
||||
upsdebugx (3, "System ACPI Power State: status string");
|
||||
str_count = 0;
|
||||
while (sensor_bitmask_strings[str_count])
|
||||
{
|
||||
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
|
||||
str_count++;
|
||||
}
|
||||
break;
|
||||
case IPMI_MONITORING_SENSOR_TYPE_BATTERY:
|
||||
upsdebugx (3, "Battery: status string");
|
||||
str_count = 0;
|
||||
while (sensor_bitmask_strings[str_count])
|
||||
{
|
||||
upsdebugx (3, "\t'%s'", sensor_bitmask_strings[str_count]);
|
||||
str_count++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process status if needed */
|
||||
if (psu_status != PSU_STATUS_UNKNOWN) {
|
||||
|
||||
status_init();
|
||||
|
||||
switch (psu_status)
|
||||
{
|
||||
case PSU_PRESENT:
|
||||
status_set("OL");
|
||||
break;
|
||||
case PSU_ABSENT:
|
||||
status_set("OFF");
|
||||
/* Declare stale */
|
||||
retval = -1;
|
||||
break;
|
||||
case PSU_POWER_FAILURE:
|
||||
status_set("OFF");
|
||||
break;
|
||||
}
|
||||
|
||||
status_commit();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -26,6 +26,17 @@
|
|||
|
||||
#define PW_MIB_VERSION "0.6.1"
|
||||
|
||||
/* TODO: more sysOID and MIBs support:
|
||||
*
|
||||
* Powerware UPS (Ingrasys X-SLOT and BD-SLOT): ".1.3.6.1.4.1.534.1"
|
||||
* Powerware PXGX cards: ".1.3.6.1.4.1.534.2.12"
|
||||
* PXGX 2000 cards (UPS): Get xupsIdentModel (".1.3.6.1.4.1.534.1.1.2.0")
|
||||
* PXGX 1000 cards (PDU/RPP/RPM): Get pduNumPanels ".1.3.6.1.4.1.534.6.6.4.1.1.1.4.0"
|
||||
*/
|
||||
|
||||
/* Powerware UPS (Ingrasys X-SLOT and BD-SLOT) */
|
||||
#define POWERWARE_SYSOID ".1.3.6.1.4.1.534.1"
|
||||
|
||||
/* SNMP OIDs set */
|
||||
#define PW_OID_MFR_NAME "1.3.6.1.4.1.534.1.1.1.0" /* XUPS-MIB::xupsIdentManufacturer.0 */
|
||||
#define PW_OID_MODEL_NAME "1.3.6.1.4.1.534.1.1.2.0" /* XUPS-MIB::xupsIdentModel.0 */
|
||||
|
@ -313,4 +324,4 @@ static snmp_info_t pw_mib[] = {
|
|||
{ NULL, 0, 0, NULL, NULL, 0, NULL }
|
||||
} ;
|
||||
|
||||
mib2nut_info_t powerware = { "pw", PW_MIB_VERSION, "", PW_OID_MODEL_NAME, pw_mib };
|
||||
mib2nut_info_t powerware = { "pw", PW_MIB_VERSION, "", PW_OID_MODEL_NAME, pw_mib, POWERWARE_SYSOID };
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
#define RARITAN_MIB_VERSION "0.4"
|
||||
|
||||
/* Raritan MIB
|
||||
* this one uses the Revelation MIB, with a different entry point */
|
||||
* this one uses the same MIB as Eaton Revelation,
|
||||
* but with a different entry point */
|
||||
#define RARITAN_BASE_OID ".1.3.6.1.4.1.13742"
|
||||
#define RARITAN_SYSOID RARITAN_BASE_OID
|
||||
#define RARITAN_OID_MODEL_NAME ".1.3.6.1.4.1.13742.1.1.12.0"
|
||||
|
||||
#define DO_OFF 0
|
||||
|
@ -119,4 +121,4 @@ static snmp_info_t raritan_mib[] = {
|
|||
{ NULL, 0, 0, NULL, NULL, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
mib2nut_info_t raritan = { "raritan", RARITAN_MIB_VERSION, "", RARITAN_OID_MODEL_NAME, raritan_mib };
|
||||
mib2nut_info_t raritan = { "raritan", RARITAN_MIB_VERSION, "", RARITAN_OID_MODEL_NAME, raritan_mib, RARITAN_SYSOID };
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Based on NetSNMP API (Simple Network Management Protocol V1-2)
|
||||
*
|
||||
* Copyright (C)
|
||||
* 2002 - 2010 Arnaud Quette <arnaud.quette@free.fr>
|
||||
* 2002 - 2011 Arnaud Quette <arnaud.quette@free.fr>
|
||||
* 2002 - 2006 Dmitry Frolov <frolov@riss-telecom.ru>
|
||||
* J.W. Hoogervorst <jeroen@hoogervorst.net>
|
||||
* Niels Baggesen <niels@baggesen.net>
|
||||
|
@ -53,6 +53,7 @@ static mib2nut_info_t *mib2nut[] = {
|
|||
&powerware,
|
||||
&aphel_genesisII,
|
||||
&aphel_revelation,
|
||||
&eaton_marlin,
|
||||
&raritan,
|
||||
&baytech,
|
||||
&compaq,
|
||||
|
@ -79,7 +80,7 @@ const char *mibvers;
|
|||
static void disable_transfer_oids(void);
|
||||
|
||||
#define DRIVER_NAME "Generic SNMP UPS driver"
|
||||
#define DRIVER_VERSION "0.50"
|
||||
#define DRIVER_VERSION "0.56"
|
||||
|
||||
/* driver description structure */
|
||||
upsdrv_info_t upsdrv_info = {
|
||||
|
@ -101,6 +102,9 @@ time_t lastpoll = 0;
|
|||
* automatically guessed at the first pass */
|
||||
int outlet_index_base = -1;
|
||||
|
||||
/* sysOID location */
|
||||
#define SYSOID_OID ".1.3.6.1.2.1.1.2.0"
|
||||
|
||||
/* ---------------------------------------------
|
||||
* driver functions implementations
|
||||
* --------------------------------------------- */
|
||||
|
@ -144,6 +148,7 @@ void upsdrv_updateinfo(void)
|
|||
upsdebugx(1,"SNMP UPS driver : entering upsdrv_updateinfo()");
|
||||
|
||||
/* only update every pollfreq */
|
||||
/* FIXME: update status (SU_STATUS_*), à la usbhid-ups, in between */
|
||||
if (time(NULL) > (lastpoll + pollfreq)) {
|
||||
|
||||
status_init();
|
||||
|
@ -257,12 +262,20 @@ void upsdrv_cleanup(void)
|
|||
|
||||
void nut_snmp_init(const char *type, const char *hostname)
|
||||
{
|
||||
char *ns_options = NULL;
|
||||
const char *community, *version;
|
||||
const char *secLevel = NULL, *authPassword, *privPassword;
|
||||
const char *authProtocol, *privProtocol;
|
||||
|
||||
upsdebugx(2, "SNMP UPS driver : entering nut_snmp_init(%s)", type);
|
||||
|
||||
/* Force numeric OIDs resolution (ie, do not resolve to textual names)
|
||||
* This is mostly for the convenience of debug output */
|
||||
ns_options = snmp_out_toggle_options("n");
|
||||
if (ns_options != NULL) {
|
||||
upsdebugx(2, "Failed to enable numeric OIDs resolution");
|
||||
}
|
||||
|
||||
/* Initialize the SNMP library */
|
||||
init_snmp(type);
|
||||
|
||||
|
@ -316,9 +329,11 @@ void nut_snmp_init(const char *type, const char *hostname)
|
|||
case SNMP_SEC_LEVEL_AUTHNOPRIV:
|
||||
if (authPassword == NULL)
|
||||
fatalx(EXIT_FAILURE, "authPassword is required for SNMPv3 in %s mode", secLevel);
|
||||
break;
|
||||
case SNMP_SEC_LEVEL_AUTHPRIV:
|
||||
if ((authPassword == NULL) || (privPassword == NULL))
|
||||
fatalx(EXIT_FAILURE, "authPassword and privPassword are required for SNMPv3 in %s mode", secLevel);
|
||||
break;
|
||||
default:
|
||||
case SNMP_SEC_LEVEL_NOAUTH:
|
||||
/* nothing else needed */
|
||||
|
@ -342,12 +357,15 @@ void nut_snmp_init(const char *type, const char *hostname)
|
|||
|
||||
/* set the authentication key to a MD5/SHA1 hashed version of our
|
||||
* passphrase (must be at least 8 characters long) */
|
||||
if (generate_Ku(g_snmp_sess.securityAuthProto,
|
||||
if(g_snmp_sess.securityLevel != SNMP_SEC_LEVEL_NOAUTH) {
|
||||
if (generate_Ku(g_snmp_sess.securityAuthProto,
|
||||
g_snmp_sess.securityAuthProtoLen,
|
||||
(u_char *) privPassword, strlen(privPassword),
|
||||
(u_char *) authPassword, strlen(authPassword),
|
||||
g_snmp_sess.securityAuthKey,
|
||||
&g_snmp_sess.securityAuthKeyLen) != SNMPERR_SUCCESS) {
|
||||
fatalx(EXIT_FAILURE, "Error generating Ku from authentication pass phrase");
|
||||
&g_snmp_sess.securityAuthKeyLen) !=
|
||||
SNMPERR_SUCCESS) {
|
||||
fatalx(EXIT_FAILURE, "Error generating Ku from authentication pass phrase");
|
||||
}
|
||||
}
|
||||
|
||||
privProtocol = testvar(SU_VAR_PRIVPROT) ? getval(SU_VAR_PRIVPROT) : "DES";
|
||||
|
@ -362,6 +380,20 @@ void nut_snmp_init(const char *type, const char *hostname)
|
|||
}
|
||||
else
|
||||
fatalx(EXIT_FAILURE, "Bad SNMPv3 authProtocol: %s", authProtocol);
|
||||
|
||||
/* set the privacy key to a MD5/SHA1 hashed version of our
|
||||
* passphrase (must be at least 8 characters long) */
|
||||
if(g_snmp_sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV) {
|
||||
g_snmp_sess.securityPrivKeyLen = USM_PRIV_KU_LEN;
|
||||
if (generate_Ku(g_snmp_sess.securityAuthProto,
|
||||
g_snmp_sess.securityAuthProtoLen,
|
||||
(u_char *) privPassword, strlen(privPassword),
|
||||
g_snmp_sess.securityPrivKey,
|
||||
&g_snmp_sess.securityPrivKeyLen) !=
|
||||
SNMPERR_SUCCESS) {
|
||||
fatalx(EXIT_FAILURE, "Error generating Ku from privacy pass phrase");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
fatalx(EXIT_FAILURE, "Bad SNMP version: %s", version);
|
||||
|
@ -447,6 +479,8 @@ bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *
|
|||
size_t len = 0;
|
||||
struct snmp_pdu *pdu;
|
||||
|
||||
upsdebugx(3, "Entering nut_snmp_get_str()");
|
||||
|
||||
/* zero out buffer. */
|
||||
memset(buf, 0, buf_len);
|
||||
|
||||
|
@ -483,11 +517,13 @@ bool_t nut_snmp_get_str(const char *OID, char *buf, size_t buf_len, info_lkp_t *
|
|||
/* convert timeticks to seconds */
|
||||
len = snprintf(buf, buf_len, "%ld", *pdu->variables->val.integer / 100);
|
||||
break;
|
||||
case ASN_OBJECT_ID:
|
||||
len = snprint_objid (buf, buf_len, pdu->variables->val.objid, pdu->variables->val_len / sizeof(oid));
|
||||
break;
|
||||
default:
|
||||
upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x received from %s",
|
||||
upsdebugx(2, "[%s] unhandled ASN 0x%x received from %s",
|
||||
upsname?upsname:device_name, pdu->variables->type, OID);
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
snmp_free_pdu(pdu);
|
||||
|
@ -673,13 +709,19 @@ void su_setinfo(snmp_info_t *su_info_p, const char *value)
|
|||
if (SU_TYPE(su_info_p) == SU_TYPE_CMD)
|
||||
return;
|
||||
|
||||
if (strcasecmp(su_info_p->info_type, "ups.status")) {
|
||||
if (strcasecmp(su_info_p->info_type, "ups.status"))
|
||||
{
|
||||
if (value != NULL)
|
||||
dstate_setinfo(su_info_p->info_type, "%s", value);
|
||||
else
|
||||
dstate_setinfo(su_info_p->info_type, "%s", su_info_p->dfl);
|
||||
|
||||
dstate_setflags(su_info_p->info_type, su_info_p->info_flags);
|
||||
dstate_setaux(su_info_p->info_type, su_info_p->info_len);
|
||||
|
||||
/* Commit the current value, to avoid staleness with huge
|
||||
* data collections on slow devices */
|
||||
dstate_dataok();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -713,36 +755,119 @@ snmp_info_t *su_find_info(const char *type)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* Try to find the MIB using sysOID matching.
|
||||
* Return a pointer to a mib2nut definition if found, NULL otherwise */
|
||||
mib2nut_info_t *match_sysoid()
|
||||
{
|
||||
char sysOID_buf[LARGEBUF];
|
||||
oid device_sysOID[MAX_OID_LEN];
|
||||
size_t device_sysOID_len = MAX_OID_LEN;
|
||||
oid mib2nut_sysOID[MAX_OID_LEN];
|
||||
size_t mib2nut_sysOID_len = MAX_OID_LEN;
|
||||
int i;
|
||||
|
||||
/* Retrieve sysOID value of this device */
|
||||
if (nut_snmp_get_str(SYSOID_OID, sysOID_buf, sizeof(sysOID_buf), NULL))
|
||||
{
|
||||
upsdebugx(1, "match_sysoid: device sysOID value = %s", sysOID_buf);
|
||||
|
||||
/* Build OIDs for comparison */
|
||||
if (!read_objid(sysOID_buf, device_sysOID, &device_sysOID_len))
|
||||
{
|
||||
upsdebugx(2, "match_sysoid: can't build device_sysOID %s: %s",
|
||||
sysOID_buf, snmp_api_errstring(snmp_errno));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Now, iterate on mib2nut definitions */
|
||||
for (i = 0; mib2nut[i] != NULL; i++)
|
||||
{
|
||||
upsdebugx(1, "match_sysoid: checking MIB %s", mib2nut[i]->mib_name);
|
||||
|
||||
if (mib2nut[i]->sysOID == NULL)
|
||||
continue;
|
||||
|
||||
/* Clear variables */
|
||||
memset(mib2nut_sysOID, 0, MAX_OID_LEN);
|
||||
mib2nut_sysOID_len = MAX_OID_LEN;
|
||||
|
||||
if (!read_objid(mib2nut[i]->sysOID, mib2nut_sysOID, &mib2nut_sysOID_len))
|
||||
{
|
||||
upsdebugx(2, "match_sysoid: can't build OID %s: %s",
|
||||
sysOID_buf, snmp_api_errstring(snmp_errno));
|
||||
|
||||
/* Try to continue anyway! */
|
||||
continue;
|
||||
}
|
||||
/* Now compare these */
|
||||
upsdebugx(1, "match_sysoid: comparing %s with %s", sysOID_buf, mib2nut[i]->sysOID);
|
||||
if (!netsnmp_oid_equals(device_sysOID, device_sysOID_len, mib2nut_sysOID, mib2nut_sysOID_len))
|
||||
{
|
||||
upsdebugx(2, "match_sysoid: sysOID matches MIB '%s'!", mib2nut[i]->mib_name);
|
||||
return mib2nut[i];
|
||||
}
|
||||
}
|
||||
/* Yell all to call for user report */
|
||||
upslogx(LOG_ERR, "No matching MIB found for sysOID '%s'! " \
|
||||
"Please report it to NUT developers, with the 'mib' paramater for your devices",
|
||||
sysOID_buf);
|
||||
}
|
||||
else
|
||||
upsdebugx(2, "Can't get sysOID value");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Load the right snmp_info_t structure matching mib parameter */
|
||||
bool_t load_mib2nut(const char *mib)
|
||||
{
|
||||
int i;
|
||||
char buf[LARGEBUF];
|
||||
mib2nut_info_t *m2n = NULL;
|
||||
|
||||
upsdebugx(2, "SNMP UPS driver : entering load_mib2nut(%s)", mib);
|
||||
|
||||
/* FIXME: first try SysOID (.1.3.6.1.2.1.1.2)
|
||||
* to speed up detection if mib==auto
|
||||
* This is an indirection on the MIB's entry point
|
||||
* examples:
|
||||
* APHEL-GENESIS-II-MIB => .iso.org.dod.internet.private.enterprises.17373
|
||||
* APHEL Revelation MIB => .iso.org.dod.internet.private.enterprises.534.6.6.6
|
||||
*/
|
||||
for (i = 0; mib2nut[i] != NULL; i++) {
|
||||
if (strcmp(mib, "auto") && strcmp(mib, mib2nut[i]->mib_name)) {
|
||||
continue;
|
||||
/* First, try to match against sysOID, if no MIB was provided.
|
||||
* This should speed up init stage
|
||||
* (Note: sysOID points the device main MIB entry point) */
|
||||
if (!strcmp(mib, "auto"))
|
||||
{
|
||||
upsdebugx(1, "trying the new match_sysoid() method");
|
||||
m2n = match_sysoid();
|
||||
}
|
||||
|
||||
/* Otherwise, revert to the classic method */
|
||||
if (m2n == NULL)
|
||||
{
|
||||
for (i = 0; mib2nut[i] != NULL; i++) {
|
||||
/* Is there already a MIB name provided? */
|
||||
if (strcmp(mib, "auto") && strcmp(mib, mib2nut[i]->mib_name)) {
|
||||
continue;
|
||||
}
|
||||
upsdebugx(1, "load_mib2nut: trying classic method with '%s' mib", mib2nut[i]->mib_name);
|
||||
|
||||
/* Classic method: test an OID specific to this MIB */
|
||||
if (!nut_snmp_get_str(mib2nut[i]->oid_auto_check, buf, sizeof(buf), NULL)) {
|
||||
continue;
|
||||
}
|
||||
/* MIB found */
|
||||
m2n = mib2nut[i];
|
||||
break;
|
||||
}
|
||||
upsdebugx(1, "load_mib2nut: trying %s mib", mib2nut[i]->mib_name);
|
||||
if (!nut_snmp_get_str(mib2nut[i]->oid_auto_check, buf, sizeof(buf), NULL)) {
|
||||
continue;
|
||||
}
|
||||
snmp_info = mib2nut[i]->snmp_info;
|
||||
OID_pwr_status = mib2nut[i]->oid_pwr_status;
|
||||
mibname = mib2nut[i]->mib_name;
|
||||
mibvers = mib2nut[i]->mib_version;
|
||||
}
|
||||
|
||||
/* Store the result, if any */
|
||||
if (m2n != NULL)
|
||||
{
|
||||
snmp_info = m2n->snmp_info;
|
||||
OID_pwr_status = m2n->oid_pwr_status;
|
||||
mibname = m2n->mib_name;
|
||||
mibvers = m2n->mib_version;
|
||||
upsdebugx(1, "load_mib2nut: using %s mib", mibname);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Did we find something or is it really an unknown mib */
|
||||
if (strcmp(mib, "auto") != 0) {
|
||||
fatalx(EXIT_FAILURE, "Unknown mibs value: %s", mib);
|
||||
|
@ -852,17 +977,25 @@ void free_info(snmp_info_t *su_info_p)
|
|||
int base_snmp_outlet_index(const char *OID_template)
|
||||
{
|
||||
int base_index = outlet_index_base;
|
||||
char test_OID[SU_INFOSIZE];
|
||||
|
||||
if (outlet_index_base == -1)
|
||||
{
|
||||
/* not initialised yet */
|
||||
char test_OID[SU_INFOSIZE];
|
||||
for (base_index = 0 ; base_index < 2 ; base_index++) {
|
||||
sprintf(test_OID, OID_template, base_index);
|
||||
if (nut_snmp_get(test_OID) != NULL)
|
||||
break;
|
||||
/* Workaround for Eaton Marlin, while waiting for a FW fix and
|
||||
* a driver rewrite (advanced hooks) */
|
||||
if ((mibname != NULL) && (!strncmp(mibname, "eaton_epdu", 11)))
|
||||
{
|
||||
upsdebugx(3, "Appying Eaton Marlin workaround");
|
||||
outlet_index_base = base_index = 1;
|
||||
} else {
|
||||
for (base_index = 0 ; base_index < 2 ; base_index++) {
|
||||
sprintf(test_OID, OID_template, base_index);
|
||||
if (nut_snmp_get(test_OID) != NULL)
|
||||
break;
|
||||
}
|
||||
outlet_index_base = base_index;
|
||||
}
|
||||
outlet_index_base = base_index;
|
||||
}
|
||||
upsdebugx(3, "base_snmp_outlet_index: %i", outlet_index_base);
|
||||
return base_index;
|
||||
|
@ -1066,8 +1199,9 @@ bool_t snmp_ups_walk(int mode)
|
|||
instantiate_info(su_info_p, &cur_info_p);
|
||||
|
||||
for (cur_outlet_number = base_snmp_outlet_index(su_info_p->OID) ;
|
||||
cur_outlet_number < outlet_count ; cur_outlet_number++) {
|
||||
|
||||
cur_outlet_number < (outlet_count + base_snmp_outlet_index(su_info_p->OID)) ;
|
||||
cur_outlet_number++)
|
||||
{
|
||||
cur_nut_index = cur_outlet_number + base_nut_outlet_offset();
|
||||
sprintf((char*)cur_info_p.info_type, su_info_p->info_type,
|
||||
cur_nut_index);
|
||||
|
|
|
@ -75,6 +75,10 @@ for each OID request we made), instead of sending many small packets
|
|||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
|
||||
/* Force numeric OIDs by disabling MIB loading */
|
||||
#define DISABLE_MIB_LOADING 1
|
||||
|
||||
|
||||
#define DEFAULT_POLLFREQ 30 /* in seconds */
|
||||
|
||||
/* use explicit booleans */
|
||||
|
@ -193,11 +197,13 @@ typedef struct {
|
|||
#define SU_ERR_RATE 100 /* only print every nth error once limiting starts */
|
||||
|
||||
typedef struct {
|
||||
const char *mib_name;
|
||||
const char *mib_version;
|
||||
const char *oid_pwr_status;
|
||||
const char *oid_auto_check;
|
||||
snmp_info_t *snmp_info; /* pointer to the good Snmp2Nut lookup data */
|
||||
const char *mib_name;
|
||||
const char *mib_version;
|
||||
const char *oid_pwr_status;
|
||||
const char *oid_auto_check; /* FIXME: rename to SysOID */
|
||||
snmp_info_t *snmp_info; /* pointer to the good Snmp2Nut lookup data */
|
||||
const char *sysOID; /* OID to match against sysOID, aka MIB
|
||||
* main entry point */
|
||||
|
||||
} mib2nut_info_t;
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ int USBNewExactMatcher(USBDeviceMatcher_t **matcher, USBDevice_t *hd)
|
|||
USBDevice_t *data;
|
||||
|
||||
m = malloc(sizeof(*m));
|
||||
if (!matcher) {
|
||||
if (!m) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue