Imported Upstream version 2.6.2

This commit is contained in:
Arnaud Quette 2011-09-29 20:14:46 +02:00
parent a367d9bc54
commit 45043b58d0
246 changed files with 18228 additions and 1415 deletions

View file

@ -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,

View file

@ -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@

View file

@ -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

File diff suppressed because it is too large Load diff

291
drivers/apcsmart-old.h Normal file
View 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 },
};

File diff suppressed because it is too large Load diff

View file

@ -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
View 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
View 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

View file

@ -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;
}

View file

@ -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

View file

@ -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) {

View file

@ -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);

View file

@ -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" },

View file

@ -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++) {

View file

@ -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 };

View file

@ -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 */

View file

@ -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 };

View file

@ -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) {

View file

@ -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

View file

@ -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 };

View file

@ -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");

View file

@ -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
View 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
View 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
View 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;
}

View file

@ -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 };

View file

@ -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 };

View file

@ -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);

View file

@ -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;

View file

@ -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;
}